diff --git a/lib/Doctrine/ORM/Mapping/OneToManyMapping.php b/lib/Doctrine/ORM/Mapping/OneToManyMapping.php index 45a3cf75d..0dabd0ec0 100644 --- a/lib/Doctrine/ORM/Mapping/OneToManyMapping.php +++ b/lib/Doctrine/ORM/Mapping/OneToManyMapping.php @@ -135,6 +135,6 @@ class OneToManyMapping extends AssociationMapping } } - $persister->loadOneToManyCollection($conditions, $targetCollection); + $persister->loadOneToManyCollection($this, $conditions, $targetCollection); } } diff --git a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php index 927d3c9fb..7e0e4a845 100644 --- a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php @@ -540,14 +540,20 @@ class StandardEntityPersister /** * Loads a collection of entities in a one-to-many association. * + * @param OneToManyMapping $assoc * @param array $criteria The criteria by which to select the entities. * @param PersistentCollection The collection to fill. */ - public function loadOneToManyCollection(array $criteria, PersistentCollection $coll) + public function loadOneToManyCollection($assoc, array $criteria, PersistentCollection $coll) { $owningAssoc = $this->_class->associationMappings[$coll->getMapping()->mappedByFieldName]; $sql = $this->_getSelectEntitiesSql($criteria, $owningAssoc); + + if ($assoc->orderBy !== null) { + $sql .= ' ORDER BY '.str_replace('%alias%', $this->_class->getTableName(), $assoc->orderBy); + } + $params = array_values($criteria); if ($this->_sqlLogger !== null) { @@ -565,6 +571,7 @@ class StandardEntityPersister /** * Loads a collection of entities of a many-to-many association. * + * @param ManyToManyMapping $assoc * @param array $criteria * @param PersistentCollection $coll The collection to fill. */ @@ -716,7 +723,8 @@ class StandardEntityPersister /** * Gets the SQL to select a collection of entities in a many-many association. - * + * + * @param ManyToManyMapping $assoc * @param array $criteria * @return string */ @@ -750,11 +758,16 @@ class StandardEntityPersister $columnName = $joinTableName . '.' . $owningAssoc->getQuotedJoinColumnName($joinColumn, $this->_platform); $conditionSql .= $columnName . ' = ?'; } + + $orderBySql = ''; + if ($manyToMany->orderBy !== null) { + $orderBySql = ' ORDER BY '.str_replace('%alias%', $this->_class->getTableName(), $manyToMany->orderBy); + } return 'SELECT ' . $this->_getSelectColumnList() . ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . $joinSql - . ' WHERE ' . $conditionSql; + . ' WHERE ' . $conditionSql . $orderBySql; } /** @override */ diff --git a/tests/Doctrine/Tests/Models/Routing/RoutingLocation.php b/tests/Doctrine/Tests/Models/Routing/RoutingLocation.php index f6f551f19..2a04275e8 100644 --- a/tests/Doctrine/Tests/Models/Routing/RoutingLocation.php +++ b/tests/Doctrine/Tests/Models/Routing/RoutingLocation.php @@ -18,4 +18,9 @@ class RoutingLocation * @Column(type="string") */ public $name; + + public function getName() + { + return $this->name; + } } \ No newline at end of file diff --git a/tests/Doctrine/Tests/Models/Routing/RoutingRoute.php b/tests/Doctrine/Tests/Models/Routing/RoutingRoute.php index 906c4bc59..d48df64f2 100644 --- a/tests/Doctrine/Tests/Models/Routing/RoutingRoute.php +++ b/tests/Doctrine/Tests/Models/Routing/RoutingRoute.php @@ -17,14 +17,21 @@ class RoutingRoute public $id; /** - * @ManyToMany(targetEntity="Doctrine\Tests\Models\Routing\RoutingLeg", cascade={"all"}) + * @ManyToMany(targetEntity="RoutingLeg", cascade={"all"}) * @JoinTable(name="RoutingRouteLegs", * joinColumns={@JoinColumn(name="route_id", referencedColumnName="id")}, * inverseJoinColumns={@JoinColumn(name="leg_id", referencedColumnName="id", unique=true)} * ) + * @OrderBy("%alias%.departureDate ASC") */ public $legs; + /** + * @OneToMany(targetEntity="RoutingRouteBooking", mappedBy="route") + * @OrderBy("%alias%.passengerName ASC") + */ + public $bookings = array(); + public function __construct() { $this->legs = new ArrayCollection(); diff --git a/tests/Doctrine/Tests/Models/Routing/RoutingRouteBooking.php b/tests/Doctrine/Tests/Models/Routing/RoutingRouteBooking.php new file mode 100644 index 000000000..ea2f31f60 --- /dev/null +++ b/tests/Doctrine/Tests/Models/Routing/RoutingRouteBooking.php @@ -0,0 +1,32 @@ +passengerName; + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php new file mode 100644 index 000000000..d67e1f1ec --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php @@ -0,0 +1,93 @@ +useModelSet('routing'); + parent::setUp(); + + $locations = array("Berlin", "Bonn", "Brasilia", "Atlanta"); + + foreach ($locations AS $locationName) { + $location = new RoutingLocation(); + $location->name = $locationName; + $this->_em->persist($location); + $this->locations[$locationName] = $location; + } + $this->_em->flush(); + } + + public function testLazyManyToManyCollection_IsRetrievedWithOrderByClause() + { + $route = new RoutingRoute(); + + $leg1 = new RoutingLeg(); + $leg1->fromLocation = $this->locations['Berlin']; + $leg1->toLocation = $this->locations['Bonn']; + $leg1->departureDate = new \DateTime("now"); + $leg1->arrivalDate = new \DateTime("now +5 hours"); + + $leg2 = new RoutingLeg(); + $leg2->fromLocation = $this->locations['Bonn']; + $leg2->toLocation = $this->locations['Brasilia']; + $leg2->departureDate = new \DateTime("now +6 hours"); + $leg2->arrivalDate = new \DateTime("now +24 hours"); + + $route->legs[] = $leg2; + $route->legs[] = $leg1; + + $this->_em->persist($route); + $this->_em->flush(); + $routeId = $route->id; + $this->_em->clear(); + + $route = $this->_em->find('Doctrine\Tests\Models\Routing\RoutingRoute', $routeId); + + $this->assertEquals(2, count($route->legs)); + $this->assertEquals("Berlin", $route->legs[0]->fromLocation->getName()); + $this->assertEquals("Bonn", $route->legs[1]->fromLocation->getName()); + } + + public function testLazyOneToManyCollection_IsRetrievedWithOrderByClause() + { + $route = new RoutingRoute(); + + $this->_em->persist($route); + $this->_em->flush(); + $routeId = $route->id; + + $booking1 = new RoutingRouteBooking(); + $booking1->passengerName = "Guilherme"; + $booking2 = new RoutingRouteBooking(); + $booking2->passengerName = "Benjamin"; + + $route->bookings[] = $booking1; + $booking1->route = $route; + $route->bookings[] = $booking2; + $booking2->route = $route; + + $this->_em->persist($booking1); + $this->_em->persist($booking2); + + $this->_em->flush(); + $this->_em->clear(); + + $route = $this->_em->find('Doctrine\Tests\Models\Routing\RoutingRoute', $routeId); + + $this->assertEquals(2, count($route->bookings)); + $this->assertEquals('Benjamin', $route->bookings[0]->getPassengerName()); + $this->assertEquals('Guilherme', $route->bookings[1]->getPassengerName()); + } +} \ No newline at end of file