1
0
mirror of synced 2025-01-27 18:41:46 +03:00

[2.0] DDC-336 - Support specification of an OrderBy SQL snippet in OneToMany and ManyToMany Associations in Annotation, XML and YAML Drivers

This commit is contained in:
beberlei 2010-02-14 19:38:22 +00:00
parent e83f1517ad
commit ab3a6cc16e
11 changed files with 113 additions and 17 deletions

View File

@ -219,6 +219,7 @@
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
<xs:attribute name="order-by" type="xs:string" />
</xs:complexType>
<xs:complexType name="one-to-many">
@ -230,6 +231,7 @@
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
<xs:attribute name="order-by" type="xs:string" />
</xs:complexType>
<xs:complexType name="many-to-one">

View File

@ -302,6 +302,11 @@ class AnnotationDriver implements Driver
$mapping['cascade'] = $oneToManyAnnot->cascade;
$mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $oneToManyAnnot->fetch);
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
}
$metadata->mapOneToMany($mapping);
} else if ($manyToOneAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToOne')) {
$mapping['joinColumns'] = $joinColumns;
@ -348,6 +353,11 @@ class AnnotationDriver implements Driver
$mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
$mapping['cascade'] = $manyToManyAnnot->cascade;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $manyToManyAnnot->fetch);
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
}
$metadata->mapManyToMany($mapping);
}
}

View File

@ -124,6 +124,8 @@ final class SequenceGenerator extends Annotation {
}
final class ChangeTrackingPolicy extends Annotation {}
final class OrderBy extends Annotation {}
/* Annotations for lifecycle callbacks */
final class HasLifecycleCallbacks extends Annotation {}
final class PrePersist extends Annotation {}

View File

@ -267,6 +267,10 @@ class XmlDriver extends AbstractFileDriver
$mapping['orphanRemoval'] = (bool)$oneToManyElement->{'orphan-removal'};
}
if (isset($oneToManyElement['order-by'])) {
$mapping['orderBy'] = (string)$oneToManyElement['order-by'];
}
$metadata->mapOneToMany($mapping);
}
}
@ -354,6 +358,10 @@ class XmlDriver extends AbstractFileDriver
$mapping['orphanRemoval'] = (bool)$manyToManyElement->{'orphan-removal'};
}
if (isset($manyToManyElement['order-by'])) {
$mapping['orderBy'] = (string)$manyToManyElement['order-by'];
}
$metadata->mapManyToMany($mapping);
}
}

View File

@ -279,6 +279,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['cascade'] = $oneToManyElement['cascade'];
}
if (isset($oneToManyElement['orderBy'])) {
$mapping['orderBy'] = $oneToManyElement['orderBy'];
}
$metadata->mapOneToMany($mapping);
}
}
@ -366,6 +370,10 @@ class YamlDriver extends AbstractFileDriver
$mapping['cascade'] = $manyToManyElement['cascade'];
}
if (isset($manyToManyElement['orderBy'])) {
$mapping['orderBy'] = $manyToManyElement['orderBy'];
}
$metadata->mapManyToMany($mapping);
}
}

View File

@ -60,6 +60,11 @@ class ManyToManyMapping extends AssociationMapping
/** FUTURE: The key column mapping, if any. The key column holds the keys of the Collection. */
//public $keyColumn;
/**
* Order this collection by the given SQL snippet.
*/
public $orderBy = null;
/**
* Initializes a new ManyToManyMapping.
*
@ -135,6 +140,10 @@ class ManyToManyMapping extends AssociationMapping
$this->joinTableColumns[] = $inverseJoinColumn['name'];
}
}
if (isset($mapping['orderBy'])) {
$this->orderBy = $mapping['orderBy'];
}
}
public function getJoinTableColumnNames()

View File

@ -51,6 +51,11 @@ class OneToManyMapping extends AssociationMapping
/** FUTURE: The key column mapping, if any. The key column holds the keys of the Collection. */
//public $keyColumn;
/**
* Order this collection by the given SQL snippet.
*/
public $orderBy = null;
/**
* Initializes a new OneToManyMapping.
*
@ -79,6 +84,10 @@ class OneToManyMapping extends AssociationMapping
$this->orphanRemoval = isset($mapping['orphanRemoval']) ?
(bool) $mapping['orphanRemoval'] : false;
if (isset($mapping['orderBy'])) {
$this->orderBy = $mapping['orderBy'];
}
}
/**

View File

@ -18,9 +18,6 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$mappingDriver = $this->_loadDriver();
$class = new ClassMetadata($className);
$this->assertFalse($mappingDriver->isTransient($className));
$mappingDriver->loadMetadataForClass($className, $class);
return $class;
@ -64,7 +61,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
public function testIdentifier($class)
{
$this->assertEquals(array('id'), $class->identifier);
$this->assertEquals(ClassMetadata::GENERATOR_TYPE_AUTO, $class->getIdGeneratorType());
$this->assertEquals(ClassMetadata::GENERATOR_TYPE_AUTO, $class->getIdGeneratorType(), "ID-Generator is not ClassMetadata::GENERATOR_TYPE_AUTO");
return $class;
}
@ -116,6 +113,9 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeDetach);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeMerge);
// Test Order By
$this->assertEquals('%alias%.number ASC', $class->associationMappings['phonenumbers']->orderBy);
return $class;
}
@ -135,6 +135,8 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$this->assertTrue($class->associationMappings['groups']->isCascadeDetach);
$this->assertTrue($class->associationMappings['groups']->isCascadeMerge);
$this->assertNull($class->associationMappings['groups']->orderBy);
return $class;
}
@ -177,20 +179,57 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
}
}
class User {
private $id;
private $name;
private $email;
private $address;
private $phonenumbers;
private $groups;
/**
* @Entity
* @HasLifecycleCallbacks
* @Table(name="cms_users")
*/
class User
{
/** @Id @Column(type="int") @generatedValue(strategy="AUTO") */
public $id;
// ... rest of code omitted, irrelevant for the mapping tests
/**
* @Column(length=50, nullable=true, unique=true)
*/
public $name;
/**
* @Column(name="user_email", columnDefinition="CHAR(32) NOT NULL")
*/
public $email;
/**
* @OneToOne(targetEntity="Address", cascade={"remove"})
*/
public $address;
/**
*
* @OneToMany(targetEntity="Phonenumber", mappedBy="user", cascade={"persist"})
* @OrderBy("%alias%.number ASC")
*/
public $phonenumbers;
/**
* @ManyToMany(targetEntity="Group", cascade={"all"})
* @JoinTable(name="cms_user_groups",
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id", nullable=false, unique=false)},
* inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id", columnDefinition="INT NULL")}
* )
*/
public $groups;
/**
* @PrePersist
*/
public function doStuffOnPrePersist()
{
}
/**
* @PostPersist
*/
public function doStuffOnPostPersist()
{

View File

@ -7,7 +7,7 @@ use Doctrine\ORM\Events;
require_once __DIR__ . '/../../TestInit.php';
class AnnotationDriverTest extends \Doctrine\Tests\OrmTestCase
class AnnotationDriverTest extends AbstractMappingDriverTest
{
/**
* @group DDC-268
@ -27,7 +27,7 @@ class AnnotationDriverTest extends \Doctrine\Tests\OrmTestCase
*/
public function testColumnWithMissingTypeDefaultsToString()
{
$cm = new ClassMetadata('Doctrine\Tests\ORM\Mapping\InvalidColumn');
$cm = new ClassMetadata('Doctrine\Tests\ORM\Mapping\ColumnWithoutType');
$reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache());
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
$annotationDriver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader);
@ -35,14 +35,22 @@ class AnnotationDriverTest extends \Doctrine\Tests\OrmTestCase
$annotationDriver->loadMetadataForClass('Doctrine\Tests\ORM\Mapping\InvalidColumn', $cm);
$this->assertEquals('string', $cm->fieldMappings['id']['type']);
}
protected function _loadDriver()
{
$cache = new \Doctrine\Common\Cache\ArrayCache();
$reader = new \Doctrine\Common\Annotations\AnnotationReader($cache);
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
return new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader);
}
}
/**
* @Entity
*/
class InvalidColumn
class ColumnWithoutType
{
/** @Id @Column */
public $id;
}

View File

@ -24,7 +24,7 @@
<join-column name="address_id" referenced-column-name="id"/>
</one-to-one>
<one-to-many field="phonenumbers" target-entity="Phonenumber" mapped-by="user">
<one-to-many field="phonenumbers" target-entity="Phonenumber" mapped-by="user" order-by="%alias%.number ASC">
<cascade>
<cascade-persist/>
</cascade>

View File

@ -27,6 +27,7 @@ Doctrine\Tests\ORM\Mapping\User:
phonenumbers:
targetEntity: Phonenumber
mappedBy: user
orderBy: %alias%.number ASC
cascade: [ persist ]
manyToMany:
groups: