diff --git a/lib/Doctrine/ORM/Mapping/ManyToManyMapping.php b/lib/Doctrine/ORM/Mapping/ManyToManyMapping.php
index 0fbb4df8a..8ebb1c0b9 100644
--- a/lib/Doctrine/ORM/Mapping/ManyToManyMapping.php
+++ b/lib/Doctrine/ORM/Mapping/ManyToManyMapping.php
@@ -61,7 +61,11 @@ class ManyToManyMapping extends AssociationMapping
//public $keyColumn;
/**
- * Order this collection by the given SQL snippet.
+ * Order this collection by the given DQL snippet.
+ *
+ * Only simple unqualified field names and ASC|DESC are allowed
+ *
+ * @var array
*/
public $orderBy = null;
@@ -142,7 +146,18 @@ class ManyToManyMapping extends AssociationMapping
}
if (isset($mapping['orderBy'])) {
- $this->orderBy = $mapping['orderBy'];
+ $parts = explode(",", $mapping['orderBy']);
+ $orderByGroup = array();
+ foreach ($parts AS $part) {
+ $orderByItem = explode(" ", trim($part));
+ if (count($orderByItem) == 1) {
+ $orderByGroup[$orderByItem[0]] = "ASC";
+ } else {
+ $orderByGroup[$orderByItem[0]] = array_pop($orderByItem);
+ }
+ }
+
+ $this->orderBy = $orderByGroup;
}
}
diff --git a/lib/Doctrine/ORM/Mapping/OneToManyMapping.php b/lib/Doctrine/ORM/Mapping/OneToManyMapping.php
index 0dabd0ec0..0de4dcdc7 100644
--- a/lib/Doctrine/ORM/Mapping/OneToManyMapping.php
+++ b/lib/Doctrine/ORM/Mapping/OneToManyMapping.php
@@ -86,7 +86,18 @@ class OneToManyMapping extends AssociationMapping
(bool) $mapping['orphanRemoval'] : false;
if (isset($mapping['orderBy'])) {
- $this->orderBy = $mapping['orderBy'];
+ $parts = explode(",", $mapping['orderBy']);
+ $orderByGroup = array();
+ foreach ($parts AS $part) {
+ $orderByItem = explode(" ", trim($part));
+ if (count($orderByItem) == 1) {
+ $orderByGroup[$orderByItem[0]] = "ASC";
+ } else {
+ $orderByGroup[$orderByItem[0]] = array_pop($orderByItem);
+ }
+ }
+
+ $this->orderBy = $orderByGroup;
}
}
diff --git a/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php
index 7242b26b3..0879785cb 100644
--- a/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php
+++ b/lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php
@@ -294,10 +294,12 @@ class JoinedSubclassPersister extends StandardEntityPersister
* Gets the SELECT SQL to select one or more entities by a set of field criteria.
*
* @param array $criteria
- * @return string The SQL.
+ * @param AssociationMapping $assoc
+ * @param string $orderBy
+ * @return string
* @override
*/
- protected function _getSelectEntitiesSql(array &$criteria, $assoc = null)
+ protected function _getSelectEntitiesSql(array &$criteria, $assoc = null, $orderBy = null)
{
$tableAliases = array();
$aliasIndex = 1;
@@ -419,10 +421,15 @@ class JoinedSubclassPersister extends StandardEntityPersister
$conditionSql .= ' = ?';
}
+ $orderBySql = '';
+ if ($orderBy !== null) {
+ $orderBySql = $this->_getCollectionOrderBySql($orderBy, $baseTableAlias, $tableAliases);
+ }
+
return 'SELECT ' . $columnList
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $baseTableAlias
. $joinSql
- . ($conditionSql != '' ? ' WHERE ' . $conditionSql : '');
+ . ($conditionSql != '' ? ' WHERE ' . $conditionSql : '') . $orderBySql;
}
/** @override */
diff --git a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php
index 7e0e4a845..50c7b5760 100644
--- a/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php
+++ b/lib/Doctrine/ORM/Persisters/StandardEntityPersister.php
@@ -548,11 +548,7 @@ class StandardEntityPersister
{
$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);
- }
+ $sql = $this->_getSelectEntitiesSql($criteria, $owningAssoc, $assoc->orderBy);
$params = array_values($criteria);
@@ -653,9 +649,11 @@ class StandardEntityPersister
* Gets the SELECT SQL to select one or more entities by a set of field criteria.
*
* @param array $criteria
- * @return string The SQL.
+ * @param AssociationMapping $assoc
+ * @param string $orderBy
+ * @return string
*/
- protected function _getSelectEntitiesSql(array &$criteria, $assoc = null)
+ protected function _getSelectEntitiesSql(array &$criteria, $assoc = null, $orderBy = null)
{
// Construct WHERE conditions
$conditionSql = '';
@@ -676,9 +674,43 @@ class StandardEntityPersister
$conditionSql .= ' = ?';
}
+ $orderBySql = '';
+ if ($orderBy !== null) {
+ $orderBySql = $this->_getCollectionOrderBySql(
+ $orderBy, $this->_class->getQuotedTableName($this->_platform)
+ );
+ }
+
return 'SELECT ' . $this->_getSelectColumnList()
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform)
- . ($conditionSql ? ' WHERE ' . $conditionSql : '');
+ . ($conditionSql ? ' WHERE ' . $conditionSql : '') . $orderBySql;
+ }
+
+ /**
+ * Generate ORDER BY Sql Snippet for ordered collections
+ *
+ * @param array $orderBy
+ * @return string
+ */
+ protected function _getCollectionOrderBySql(array $orderBy, $baseTableAlias, $tableAliases = array())
+ {
+ $orderBySql = '';
+ foreach ($orderBy AS $fieldName => $orientation) {
+ if (!isset($this->_class->fieldMappings[$fieldName])) {
+ ORMException::unrecognizedField($fieldName);
+ }
+
+ $tableAlias = isset($this->_class->fieldMappings['inherited']) ?
+ $tableAliases[$this->_class->fieldMappings['inherited']] : $baseTableAlias;
+ $columnName = $this->_class->getQuotedColumnName($fieldName, $this->_platform);
+ if ($orderBySql != '') {
+ $orderBySql .= ', ';
+ } else {
+ $orderBySql = ' ORDER BY ';
+ }
+ $orderBySql .= $tableAlias . '.' . $columnName . ' '.$orientation;
+ }
+ return $orderBySql;
}
/**
@@ -724,7 +756,7 @@ class StandardEntityPersister
/**
* Gets the SQL to select a collection of entities in a many-many association.
*
- * @param ManyToManyMapping $assoc
+ * @param ManyToManyMapping $manyToMany
* @param array $criteria
* @return string
*/
@@ -761,7 +793,9 @@ class StandardEntityPersister
$orderBySql = '';
if ($manyToMany->orderBy !== null) {
- $orderBySql = ' ORDER BY '.str_replace('%alias%', $this->_class->getTableName(), $manyToMany->orderBy);
+ $orderBySql = $this->_getCollectionOrderBySql(
+ $manyToMany->orderBy, $this->_class->getQuotedTableName($this->_platform)
+ );
}
return 'SELECT ' . $this->_getSelectColumnList()
diff --git a/tests/Doctrine/Tests/ORM/Functional/AllTests.php b/tests/Doctrine/Tests/ORM/Functional/AllTests.php
index e3c921778..81b67c1f2 100644
--- a/tests/Doctrine/Tests/ORM/Functional/AllTests.php
+++ b/tests/Doctrine/Tests/ORM/Functional/AllTests.php
@@ -41,6 +41,8 @@ class AllTests
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\OneToOneSelfReferentialAssociationTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\OneToManySelfReferentialAssociationTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ManyToManySelfReferentialAssociationTest');
+ $suite->addTestSuite('Doctrine\Tests\ORM\Functional\OrderedCollectionTest');
+ $suite->addTestSuite('Doctrine\Tests\ORM\Functional\OrderedJoinedTableInheritanceCollectionTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\ReferenceProxyTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\LifecycleCallbackTest');
$suite->addTestSuite('Doctrine\Tests\ORM\Functional\StandardEntityPersisterTest');
diff --git a/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php
index d67e1f1ec..f44fe4798 100644
--- a/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php
+++ b/tests/Doctrine/Tests/ORM/Functional/OrderedCollectionTest.php
@@ -9,7 +9,7 @@ use Doctrine\Tests\Models\Routing\RoutingRouteBooking;
require_once __DIR__ . '/../../TestInit.php';
-class OrderedAssociationTest extends \Doctrine\Tests\OrmFunctionalTestCase
+class OrderedCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected $locations = array();
diff --git a/tests/Doctrine/Tests/ORM/Functional/OrderedJoinedTableInheritanceCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/OrderedJoinedTableInheritanceCollectionTest.php
new file mode 100644
index 000000000..4ede6056a
--- /dev/null
+++ b/tests/Doctrine/Tests/ORM/Functional/OrderedJoinedTableInheritanceCollectionTest.php
@@ -0,0 +1,121 @@
+
+ */
+class OrderedJoinedTableInheritanceCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
+{
+ protected function setUp() {
+ parent::setUp();
+ try {
+ $this->_schemaTool->createSchema(array(
+ $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\OJTIC_Pet'),
+ $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\OJTIC_Cat'),
+ $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\OJTIC_Dog'),
+ ));
+ } catch (\Exception $e) {
+ // Swallow all exceptions. We do not test the schema tool here.
+ }
+ }
+
+ public function testOrderdOneToManyCollection()
+ {
+ $dog = new OJTIC_Dog();
+ $dog->name = "Poofy";
+
+ $dog1 = new OJTIC_Dog();
+ $dog1->name = "Zampa";
+ $dog2 = new OJTIC_Dog();
+ $dog2->name = "Aari";
+
+ $dog1->mother = $dog;
+ $dog2->mother = $dog;
+
+ $dog->children[] = $dog1;
+ $dog->children[] = $dog2;
+
+ $this->_em->persist($dog);
+ $this->_em->persist($dog1);
+ $this->_em->persist($dog2);
+ $this->_em->flush();
+ $this->_em->clear();
+
+ $poofy = $this->_em->createQuery("SELECT p FROM Doctrine\Tests\ORM\Functional\OJTIC_Pet p WHERE p.name = 'Poofy'")->getSingleResult();
+
+ $this->assertEquals('Aari', $poofy->children[0]->getName());
+ $this->assertEquals('Zampa', $poofy->children[1]->getName());
+ }
+}
+
+/**
+ * @Entity
+ * @InheritanceType("JOINED")
+ * @DiscriminatorColumn(name="discr", type="string")
+ * @DiscriminatorMap({
+ * "cat" = "OJTIC_Cat",
+ * "dog" = "OJTIC_Dog"})
+ */
+abstract class OJTIC_Pet
+{
+ /**
+ * @Id
+ * @column(type="integer")
+ * @generatedValue(strategy="AUTO")
+ */
+ public $id;
+
+ /**
+ *
+ * @Column
+ */
+ public $name;
+
+ /**
+ * @ManyToOne(targetEntity="OJTIC_PET")
+ */
+ public $mother;
+
+ /**
+ * @OneToMany(targetEntity="OJTIC_Pet", mappedBy="mother")
+ * @OrderBy("name ASC")
+ */
+ public $children;
+
+ /**
+ * @ManyToMany(targetEntity="OJTIC_Pet")
+ * @JoinTable(name="OTJIC_Pet_Friends",
+ * joinColumns={@JoinColumn(name="pet_id", referencedColumnName="id")},
+ * inverseJoinColumns={@JoinColumn(name="friend_id", referencedColumnName="id")})
+ * @OrderBy("name ASC")
+ */
+ public $friends;
+
+ public function getName()
+ {
+ return $this->name;
+ }
+}
+
+/**
+ * @Entity
+ */
+class OJTIC_Cat extends OJTIC_Pet
+{
+
+}
+
+/**
+ * @Entity
+ */
+class OJTIC_Dog extends OJTIC_Pet
+{
+
+}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php
index b7c9b108f..a41c4a22a 100644
--- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php
+++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php
@@ -114,7 +114,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeMerge);
// Test Order By
- $this->assertEquals('%alias%.number ASC', $class->associationMappings['phonenumbers']->orderBy);
+ $this->assertEquals(array('number' => 'ASC'), $class->associationMappings['phonenumbers']->orderBy);
return $class;
}
@@ -207,7 +207,7 @@ class User
/**
*
* @OneToMany(targetEntity="Phonenumber", mappedBy="user", cascade={"persist"})
- * @OrderBy("%alias%.number ASC")
+ * @OrderBy("number ASC")
*/
public $phonenumbers;
diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml
index 1a344790e..c28baa48e 100644
--- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml
+++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml
@@ -24,7 +24,7 @@
-
+
diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml
index 450dfd7e5..2e9ed0302 100644
--- a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml
+++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.ORM.Mapping.User.dcm.yml
@@ -27,7 +27,7 @@ Doctrine\Tests\ORM\Mapping\User:
phonenumbers:
targetEntity: Phonenumber
mappedBy: user
- orderBy: %alias%.number ASC
+ orderBy: number ASC
cascade: [ persist ]
manyToMany:
groups: