Merge branch 'DDC-250'
This commit is contained in:
commit
7390030854
@ -257,6 +257,7 @@
|
|||||||
<xs:attribute name="target-entity" type="xs:string" use="required" />
|
<xs:attribute name="target-entity" type="xs:string" use="required" />
|
||||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
|
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
|
||||||
|
<xs:attribute name="index-by" type="xs:NMTOKEN" />
|
||||||
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
|
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
|
||||||
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
@ -269,6 +270,7 @@
|
|||||||
<xs:attribute name="target-entity" type="xs:string" use="required" />
|
<xs:attribute name="target-entity" type="xs:string" use="required" />
|
||||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" use="required" />
|
<xs:attribute name="mapped-by" type="xs:NMTOKEN" use="required" />
|
||||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||||
|
<xs:attribute name="index-by" type="xs:NMTOKEN" />
|
||||||
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
|
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
|
||||||
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
@ -376,6 +376,11 @@ class ClassMetadataInfo
|
|||||||
* Only valid for many-to-many mappings. Note that one-to-many associations can be mapped
|
* Only valid for many-to-many mappings. Note that one-to-many associations can be mapped
|
||||||
* through a join table by simply mapping the association as many-to-many with a unique
|
* through a join table by simply mapping the association as many-to-many with a unique
|
||||||
* constraint on the join table.
|
* constraint on the join table.
|
||||||
|
*
|
||||||
|
* - <b>indexBy</b> (string, optional, to-many only)
|
||||||
|
* Specification of a field on target-entity that is used to index the collection by.
|
||||||
|
* This field HAS to be either the primary key or a unique column. Otherwise the collection
|
||||||
|
* does not contain all the entities that are actually related.
|
||||||
*
|
*
|
||||||
* A join table definition has the following structure:
|
* A join table definition has the following structure:
|
||||||
* <pre>
|
* <pre>
|
||||||
@ -717,6 +722,11 @@ class ClassMetadataInfo
|
|||||||
}
|
}
|
||||||
$mapping['isOwningSide'] = true; // assume owning side until we hit mappedBy
|
$mapping['isOwningSide'] = true; // assume owning side until we hit mappedBy
|
||||||
|
|
||||||
|
// unset optional indexBy attribute if its empty
|
||||||
|
if (!isset($mapping['indexBy']) || !$mapping['indexBy']) {
|
||||||
|
unset($mapping['indexBy']);
|
||||||
|
}
|
||||||
|
|
||||||
// If targetEntity is unqualified, assume it is in the same namespace as
|
// If targetEntity is unqualified, assume it is in the same namespace as
|
||||||
// the sourceEntity.
|
// the sourceEntity.
|
||||||
$mapping['sourceEntity'] = $this->name;
|
$mapping['sourceEntity'] = $this->name;
|
||||||
|
@ -304,6 +304,7 @@ class AnnotationDriver implements Driver
|
|||||||
$mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
|
$mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
|
||||||
$mapping['targetEntity'] = $oneToManyAnnot->targetEntity;
|
$mapping['targetEntity'] = $oneToManyAnnot->targetEntity;
|
||||||
$mapping['cascade'] = $oneToManyAnnot->cascade;
|
$mapping['cascade'] = $oneToManyAnnot->cascade;
|
||||||
|
$mapping['indexBy'] = $oneToManyAnnot->indexBy;
|
||||||
$mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
|
$mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
|
||||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyAnnot->fetch);
|
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyAnnot->fetch);
|
||||||
|
|
||||||
@ -362,6 +363,7 @@ class AnnotationDriver implements Driver
|
|||||||
$mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
|
$mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
|
||||||
$mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
|
$mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
|
||||||
$mapping['cascade'] = $manyToManyAnnot->cascade;
|
$mapping['cascade'] = $manyToManyAnnot->cascade;
|
||||||
|
$mapping['indexBy'] = $manyToManyAnnot->indexBy;
|
||||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyAnnot->fetch);
|
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyAnnot->fetch);
|
||||||
|
|
||||||
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
|
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
|
||||||
|
@ -80,6 +80,7 @@ final class OneToMany extends Annotation {
|
|||||||
public $cascade;
|
public $cascade;
|
||||||
public $fetch = 'LAZY';
|
public $fetch = 'LAZY';
|
||||||
public $orphanRemoval = false;
|
public $orphanRemoval = false;
|
||||||
|
public $indexBy;
|
||||||
}
|
}
|
||||||
final class ManyToOne extends Annotation {
|
final class ManyToOne extends Annotation {
|
||||||
public $targetEntity;
|
public $targetEntity;
|
||||||
@ -93,6 +94,7 @@ final class ManyToMany extends Annotation {
|
|||||||
public $inversedBy;
|
public $inversedBy;
|
||||||
public $cascade;
|
public $cascade;
|
||||||
public $fetch = 'LAZY';
|
public $fetch = 'LAZY';
|
||||||
|
public $indexBy;
|
||||||
}
|
}
|
||||||
final class ElementCollection extends Annotation {
|
final class ElementCollection extends Annotation {
|
||||||
public $tableName;
|
public $tableName;
|
||||||
|
@ -309,6 +309,10 @@ class XmlDriver extends AbstractFileDriver
|
|||||||
$mapping['orderBy'] = $orderBy;
|
$mapping['orderBy'] = $orderBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($oneToManyElement->{'index-by'})) {
|
||||||
|
$mapping['indexBy'] = (string)$oneToManyElement->{'index-by'};
|
||||||
|
}
|
||||||
|
|
||||||
$metadata->mapOneToMany($mapping);
|
$metadata->mapOneToMany($mapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -415,6 +419,10 @@ class XmlDriver extends AbstractFileDriver
|
|||||||
$mapping['orderBy'] = $orderBy;
|
$mapping['orderBy'] = $orderBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($manyToManyElement->{'index-by'})) {
|
||||||
|
$mapping['indexBy'] = (string)$manyToManyElement->{'index-by'};
|
||||||
|
}
|
||||||
|
|
||||||
$metadata->mapManyToMany($mapping);
|
$metadata->mapManyToMany($mapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,6 +301,10 @@ class YamlDriver extends AbstractFileDriver
|
|||||||
$mapping['orderBy'] = $oneToManyElement['orderBy'];
|
$mapping['orderBy'] = $oneToManyElement['orderBy'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($oneToManyElement['indexBy'])) {
|
||||||
|
$mapping['indexBy'] = $oneToManyElement['indexBy'];
|
||||||
|
}
|
||||||
|
|
||||||
$metadata->mapOneToMany($mapping);
|
$metadata->mapOneToMany($mapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -404,6 +408,10 @@ class YamlDriver extends AbstractFileDriver
|
|||||||
$mapping['orderBy'] = $manyToManyElement['orderBy'];
|
$mapping['orderBy'] = $manyToManyElement['orderBy'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($manyToManyElement['indexBy'])) {
|
||||||
|
$mapping['indexBy'] = $manyToManyElement['indexBy'];
|
||||||
|
}
|
||||||
|
|
||||||
$metadata->mapManyToMany($mapping);
|
$metadata->mapManyToMany($mapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -750,15 +750,55 @@ class BasicEntityPersister
|
|||||||
public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||||
{
|
{
|
||||||
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit);
|
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit);
|
||||||
|
return $this->loadArrayFromStatement($assoc, $stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an array of entities from a given dbal statement.
|
||||||
|
*
|
||||||
|
* @param array $assoc
|
||||||
|
* @param Doctrine\DBAL\Statement $stmt
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function loadArrayFromStatement($assoc, $stmt)
|
||||||
|
{
|
||||||
$entities = array();
|
$entities = array();
|
||||||
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
if (isset($assoc['indexBy'])) {
|
||||||
$entities[] = $this->_createEntity($result);
|
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$entity = $this->_createEntity($result);
|
||||||
|
$entities[$this->_class->reflFields[$assoc['indexBy']]->getValue($entity)] = $entity;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$entities[] = $this->_createEntity($result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$stmt->closeCursor();
|
$stmt->closeCursor();
|
||||||
return $entities;
|
return $entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hydrate a collection from a given dbal statement.
|
||||||
|
*
|
||||||
|
* @param array $assoc
|
||||||
|
* @param Doctrine\DBAL\Statement $stmt
|
||||||
|
* @param PersistentCollection $coll
|
||||||
|
*/
|
||||||
|
private function loadCollectionFromStatement($assoc, $stmt, $coll)
|
||||||
|
{
|
||||||
|
if (isset($assoc['indexBy'])) {
|
||||||
|
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$entity = $this->_createEntity($result);
|
||||||
|
$coll->hydrateSet($this->_class->reflFields[$assoc['indexBy']]->getValue($entity), $entity);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$coll->hydrateAdd($this->_createEntity($result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$stmt->closeCursor();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a collection of entities of a many-to-many association.
|
* Loads a collection of entities of a many-to-many association.
|
||||||
*
|
*
|
||||||
@ -772,11 +812,7 @@ class BasicEntityPersister
|
|||||||
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
|
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
|
||||||
{
|
{
|
||||||
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity);
|
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity);
|
||||||
|
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
|
||||||
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
||||||
$coll->hydrateAdd($this->_createEntity($result));
|
|
||||||
}
|
|
||||||
$stmt->closeCursor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getManyToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
private function getManyToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||||
@ -1238,13 +1274,7 @@ class BasicEntityPersister
|
|||||||
public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||||
{
|
{
|
||||||
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit);
|
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit);
|
||||||
|
return $this->loadArrayFromStatement($assoc, $stmt);
|
||||||
$entities = array();
|
|
||||||
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
||||||
$entities[] = $this->_createEntity($result);
|
|
||||||
}
|
|
||||||
$stmt->closeCursor();
|
|
||||||
return $entities;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1259,11 +1289,7 @@ class BasicEntityPersister
|
|||||||
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
|
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
|
||||||
{
|
{
|
||||||
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity);
|
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity);
|
||||||
|
$this->loadCollectionFromStatement($assoc, $stmt, $coll);
|
||||||
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
||||||
$coll->hydrateAdd($this->_createEntity($result));
|
|
||||||
}
|
|
||||||
$stmt->closeCursor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -923,6 +923,10 @@ class Parser
|
|||||||
$token = $this->_lexer->lookahead;
|
$token = $this->_lexer->lookahead;
|
||||||
$identVariable = $this->IdentificationVariable();
|
$identVariable = $this->IdentificationVariable();
|
||||||
|
|
||||||
|
if (!isset($this->_queryComponents[$identVariable])) {
|
||||||
|
$this->semanticalError('Identification Variable ' . $identVariable .' used in join path expression but was not defined before.');
|
||||||
|
}
|
||||||
|
|
||||||
$this->match(Lexer::T_DOT);
|
$this->match(Lexer::T_DOT);
|
||||||
$this->match(Lexer::T_IDENTIFIER);
|
$this->match(Lexer::T_IDENTIFIER);
|
||||||
|
|
||||||
|
@ -750,6 +750,16 @@ class SqlWalker implements TreeWalker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($joinVarDecl->indexBy) {
|
||||||
|
// For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently.
|
||||||
|
$this->_rsm->addIndexBy(
|
||||||
|
$joinVarDecl->indexBy->simpleStateFieldPathExpression->identificationVariable,
|
||||||
|
$joinVarDecl->indexBy->simpleStateFieldPathExpression->field
|
||||||
|
);
|
||||||
|
} else if (isset($relation['indexBy'])) {
|
||||||
|
$this->_rsm->addIndexBy($joinedDqlAlias, $relation['indexBy']);
|
||||||
|
}
|
||||||
|
|
||||||
// This condition is not checking ClassMetadata::MANY_TO_ONE, because by definition it cannot
|
// This condition is not checking ClassMetadata::MANY_TO_ONE, because by definition it cannot
|
||||||
// be the owning side and previously we ensured that $assoc is always the owning side of the associations.
|
// be the owning side and previously we ensured that $assoc is always the owning side of the associations.
|
||||||
// The owning side is necessary at this point because only it contains the JoinColumn information.
|
// The owning side is necessary at this point because only it contains the JoinColumn information.
|
||||||
|
48
tests/Doctrine/Tests/Models/StockExchange/Bond.php
Normal file
48
tests/Doctrine/Tests/Models/StockExchange/Bond.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
namespace Doctrine\Tests\Models\StockExchange;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bonds have many stocks. This uses a many to many assocation and fails to model how many of a
|
||||||
|
* particular stock a bond has. But i Need a many-to-many assocation, so please bear with my modelling skills ;)
|
||||||
|
*
|
||||||
|
* @Entity
|
||||||
|
* @Table(name="exchange_bonds")
|
||||||
|
*/
|
||||||
|
class Bond
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Id @GeneratedValue @column(type="integer")
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @column(type="string")
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ManyToMany(targetEntity="Stock", indexBy="symbol")
|
||||||
|
* @JoinTable(name="exchange_bonds_stocks")
|
||||||
|
* @var Stock[]
|
||||||
|
*/
|
||||||
|
public $stocks;
|
||||||
|
|
||||||
|
public function __construct($name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addStock(Stock $stock)
|
||||||
|
{
|
||||||
|
$this->stocks[$stock->getSymbol()] = $stock;
|
||||||
|
}
|
||||||
|
}
|
56
tests/Doctrine/Tests/Models/StockExchange/Market.php
Normal file
56
tests/Doctrine/Tests/Models/StockExchange/Market.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Doctrine\Tests\Models\StockExchange;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
* @Table(name="exchange_markets")
|
||||||
|
*/
|
||||||
|
class Market
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Id @Column(type="integer") @GeneratedValue
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column(type="string")
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OneToMany(targetEntity="Stock", mappedBy="market", indexBy="symbol")
|
||||||
|
* @var Stock[]
|
||||||
|
*/
|
||||||
|
public $stocks;
|
||||||
|
|
||||||
|
public function __construct($name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->stocks = new ArrayCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addStock(Stock $stock)
|
||||||
|
{
|
||||||
|
$this->stocks[$stock->getSymbol()] = $stock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStock($symbol)
|
||||||
|
{
|
||||||
|
return $this->stocks[$symbol];
|
||||||
|
}
|
||||||
|
}
|
49
tests/Doctrine/Tests/Models/StockExchange/Stock.php
Normal file
49
tests/Doctrine/Tests/Models/StockExchange/Stock.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Doctrine\Tests\Models\StockExchange;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
* @Table(name="exchange_stocks")
|
||||||
|
*/
|
||||||
|
class Stock
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Id @GeneratedValue @Column(type="integer")
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For real this column would have to be unique=true. But I want to test behavior of non-unique overrides.
|
||||||
|
*
|
||||||
|
* @Column(type="string")
|
||||||
|
*/
|
||||||
|
private $symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column(type="decimal")
|
||||||
|
*/
|
||||||
|
private $price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ManyToOne(targetEntity="Market", inversedBy="stocks")
|
||||||
|
* @var Market
|
||||||
|
*/
|
||||||
|
private $market;
|
||||||
|
|
||||||
|
public function __construct($symbol, $initialOfferingPrice, Market $market)
|
||||||
|
{
|
||||||
|
$this->symbol = $symbol;
|
||||||
|
$this->price = $initialOfferingPrice;
|
||||||
|
$this->market = $market;
|
||||||
|
$market->addStock($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSymbol()
|
||||||
|
{
|
||||||
|
return $this->symbol;
|
||||||
|
}
|
||||||
|
}
|
@ -45,6 +45,7 @@ class AllTests
|
|||||||
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ManyToManySelfReferentialAssociationTest');
|
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ManyToManySelfReferentialAssociationTest');
|
||||||
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\OrderedCollectionTest');
|
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\OrderedCollectionTest');
|
||||||
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\OrderedJoinedTableInheritanceCollectionTest');
|
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\OrderedJoinedTableInheritanceCollectionTest');
|
||||||
|
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\IndexByAssociationTest');
|
||||||
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\CompositePrimaryKeyTest');
|
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\CompositePrimaryKeyTest');
|
||||||
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ReferenceProxyTest');
|
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ReferenceProxyTest');
|
||||||
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\LifecycleCallbackTest');
|
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\LifecycleCallbackTest');
|
||||||
|
105
tests/Doctrine/Tests/ORM/Functional/IndexByAssociationTest.php
Normal file
105
tests/Doctrine/Tests/ORM/Functional/IndexByAssociationTest.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Doctrine\Tests\ORM\Functional;
|
||||||
|
|
||||||
|
use Doctrine\Tests\Models\StockExchange\Stock;
|
||||||
|
use Doctrine\Tests\Models\StockExchange\Market;
|
||||||
|
use Doctrine\Tests\Models\StockExchange\Bond;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../TestInit.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-250
|
||||||
|
*/
|
||||||
|
class IndexByAssociationTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Doctrine\Tests\Models\StockExchange\Market
|
||||||
|
*/
|
||||||
|
private $market;
|
||||||
|
|
||||||
|
private $bond;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->useModelSet('stockexchange');
|
||||||
|
parent::setUp();
|
||||||
|
$this->loadFixture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadFixture()
|
||||||
|
{
|
||||||
|
$this->market = new Market("Some Exchange");
|
||||||
|
$stock1 = new Stock("AAPL", 10, $this->market);
|
||||||
|
$stock2 = new Stock("GOOG", 20, $this->market);
|
||||||
|
|
||||||
|
$this->bond = new Bond("MyBond");
|
||||||
|
$this->bond->addStock($stock1);
|
||||||
|
$this->bond->addStock($stock2);
|
||||||
|
|
||||||
|
$this->_em->persist($this->market);
|
||||||
|
$this->_em->persist($stock1);
|
||||||
|
$this->_em->persist($stock2);
|
||||||
|
$this->_em->persist($this->bond);
|
||||||
|
$this->_em->flush();
|
||||||
|
$this->_em->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManyToOneFinder()
|
||||||
|
{
|
||||||
|
/* @var $market Doctrine\Tests\Models\StockExchange\Market */
|
||||||
|
$market = $this->_em->find('Doctrine\Tests\Models\StockExchange\Market', $this->market->getId());
|
||||||
|
|
||||||
|
$this->assertEquals(2, count($market->stocks));
|
||||||
|
$this->assertTrue(isset($market->stocks['AAPL']), "AAPL symbol has to be key in indexed assocation.");
|
||||||
|
$this->assertTrue(isset($market->stocks['GOOG']), "GOOG symbol has to be key in indexed assocation.");
|
||||||
|
$this->assertEquals("AAPL", $market->stocks['AAPL']->getSymbol());
|
||||||
|
$this->assertEquals("GOOG", $market->stocks['GOOG']->getSymbol());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManyToOneDQL()
|
||||||
|
{
|
||||||
|
$dql = "SELECT m, s FROM Doctrine\Tests\Models\StockExchange\Market m JOIN m.stocks s WHERE m.id = ?1";
|
||||||
|
$market = $this->_em->createQuery($dql)->setParameter(1, $this->market->getId())->getSingleResult();
|
||||||
|
|
||||||
|
$this->assertEquals(2, count($market->stocks));
|
||||||
|
$this->assertTrue(isset($market->stocks['AAPL']), "AAPL symbol has to be key in indexed assocation.");
|
||||||
|
$this->assertTrue(isset($market->stocks['GOOG']), "GOOG symbol has to be key in indexed assocation.");
|
||||||
|
$this->assertEquals("AAPL", $market->stocks['AAPL']->getSymbol());
|
||||||
|
$this->assertEquals("GOOG", $market->stocks['GOOG']->getSymbol());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManyToMany()
|
||||||
|
{
|
||||||
|
$bond = $this->_em->find('Doctrine\Tests\Models\StockExchange\Bond', $this->bond->getId());
|
||||||
|
|
||||||
|
$this->assertEquals(2, count($bond->stocks));
|
||||||
|
$this->assertTrue(isset($bond->stocks['AAPL']), "AAPL symbol has to be key in indexed assocation.");
|
||||||
|
$this->assertTrue(isset($bond->stocks['GOOG']), "GOOG symbol has to be key in indexed assocation.");
|
||||||
|
$this->assertEquals("AAPL", $bond->stocks['AAPL']->getSymbol());
|
||||||
|
$this->assertEquals("GOOG", $bond->stocks['GOOG']->getSymbol());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManytoManyDQL()
|
||||||
|
{
|
||||||
|
$dql = "SELECT b, s FROM Doctrine\Tests\Models\StockExchange\Bond b JOIN b.stocks s WHERE b.id = ?1";
|
||||||
|
$bond = $this->_em->createQuery($dql)->setParameter(1, $this->bond->getId())->getSingleResult();
|
||||||
|
|
||||||
|
$this->assertEquals(2, count($bond->stocks));
|
||||||
|
$this->assertTrue(isset($bond->stocks['AAPL']), "AAPL symbol has to be key in indexed assocation.");
|
||||||
|
$this->assertTrue(isset($bond->stocks['GOOG']), "GOOG symbol has to be key in indexed assocation.");
|
||||||
|
$this->assertEquals("AAPL", $bond->stocks['AAPL']->getSymbol());
|
||||||
|
$this->assertEquals("GOOG", $bond->stocks['GOOG']->getSymbol());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDqlOverrideIndexBy()
|
||||||
|
{
|
||||||
|
$dql = "SELECT b, s FROM Doctrine\Tests\Models\StockExchange\Bond b JOIN b.stocks s INDEX BY s.id WHERE b.id = ?1";
|
||||||
|
$bond = $this->_em->createQuery($dql)->setParameter(1, $this->bond->getId())->getSingleResult();
|
||||||
|
|
||||||
|
$this->assertEquals(2, count($bond->stocks));
|
||||||
|
$this->assertFalse(isset($bond->stocks['AAPL']), "AAPL symbol not exists in re-indexed assocation.");
|
||||||
|
$this->assertFalse(isset($bond->stocks['GOOG']), "GOOG symbol not exists in re-indexed assocation.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -99,6 +99,11 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
|
|||||||
'Doctrine\Tests\Models\DDC117\DDC117ApproveChanges',
|
'Doctrine\Tests\Models\DDC117\DDC117ApproveChanges',
|
||||||
'Doctrine\Tests\Models\DDC117\DDC117Editor',
|
'Doctrine\Tests\Models\DDC117\DDC117Editor',
|
||||||
),
|
),
|
||||||
|
'stockexchange' => array(
|
||||||
|
'Doctrine\Tests\Models\StockExchange\Bond',
|
||||||
|
'Doctrine\Tests\Models\StockExchange\Stock',
|
||||||
|
'Doctrine\Tests\Models\StockExchange\Market',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
protected function useModelSet($setName)
|
protected function useModelSet($setName)
|
||||||
@ -191,6 +196,12 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
|
|||||||
$conn->executeUpdate('DELETE FROM DDC117Translation');
|
$conn->executeUpdate('DELETE FROM DDC117Translation');
|
||||||
$conn->executeUpdate('DELETE FROM DDC117Article');
|
$conn->executeUpdate('DELETE FROM DDC117Article');
|
||||||
}
|
}
|
||||||
|
if (isset($this->_usedModelSets['stockexchange'])) {
|
||||||
|
$conn->executeUpdate('DELETE FROM exchange_bonds_stocks');
|
||||||
|
$conn->executeUpdate('DELETE FROM exchange_bonds');
|
||||||
|
$conn->executeUpdate('DELETE FROM exchange_stocks');
|
||||||
|
$conn->executeUpdate('DELETE FROM exchange_markets');
|
||||||
|
}
|
||||||
|
|
||||||
$this->_em->clear();
|
$this->_em->clear();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user