1
0
mirror of synced 2025-03-27 02:13:50 +03:00

Merge branch 'DDC-1723'

This commit is contained in:
Benjamin Eberlei 2012-03-22 22:30:35 +01:00
commit 18e63f9cea
15 changed files with 245 additions and 34 deletions

View File

@ -162,6 +162,7 @@
<xs:enumeration value="IDENTITY"/>
<xs:enumeration value="AUTO"/>
<xs:enumeration value="UUID"/>
<xs:enumeration value="CUSTOM" />
</xs:restriction>
</xs:simpleType>
@ -274,6 +275,7 @@
<xs:sequence>
<xs:element name="generator" type="orm:generator" minOccurs="0" />
<xs:element name="sequence-generator" type="orm:sequence-generator" minOccurs="0" maxOccurs="1" />
<xs:element name="custom-id-generator" type="orm:custom-id-generator" minOccurs="0" maxOccurs="1" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
@ -294,6 +296,13 @@
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="custom-id-generator">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="class" type="xs:NMTOKEN" use="required" />
</xs:complexType>
<xs:complexType name="inverse-join-columns">
<xs:sequence>
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />

View File

@ -521,6 +521,14 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
case ClassMetadata::GENERATOR_TYPE_TABLE:
throw new ORMException("TableGenerator not yet implemented.");
break;
case ClassMetadata::GENERATOR_TYPE_CUSTOM:
$definition = $class->customGeneratorDefinition;
if (!class_exists($definition['class'])) {
throw new ORMException("Can't instantiate custom generator : " .
$definition['class']);
}
$class->setIdGenerator(new $definition['class']);
break;
default:
throw new ORMException("Unknown generator type: " . $class->generatorType);
}

View File

@ -99,6 +99,10 @@ class ClassMetadataInfo implements ClassMetadata
* portability is currently not guaranteed.
*/
const GENERATOR_TYPE_UUID = 6;
/**
* CUSTOM means that customer will use own ID generator that supposedly work
*/
const GENERATOR_TYPE_CUSTOM = 7;
/**
* DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time
* by doing a property-by-property comparison with the original data. This will
@ -181,6 +185,22 @@ class ClassMetadataInfo implements ClassMetadata
*/
public $rootEntityName;
/**
* READ-ONLY: The definition of custom generator. Only used for CUSTOM
* generator type
*
* The definition has the following structure:
* <code>
* array(
* 'class' => 'ClassName',
* )
* </code>
*
* @var array
* @todo Merge with tableGeneratorDefinition into generic generatorDefinition
*/
public $customGeneratorDefinition;
/**
* The name of the custom repository class used for the entity class.
* (Optional).
@ -2146,6 +2166,15 @@ class ClassMetadataInfo implements ClassMetadata
$this->idGenerator = $generator;
}
/**
* Sets definition
* @param array $definition
*/
public function setCustomGeneratorDefinition(array $definition)
{
$this->customGeneratorDefinition = $definition;
}
/**
* Sets the definition of the sequence ID generator for this class.
*

View File

@ -0,0 +1,30 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class CustomIdGenerator implements Annotation
{
/** @var string */
public $class;
}

View File

@ -343,6 +343,10 @@ class AnnotationDriver implements Driver
));
} else if ($tblGeneratorAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) {
throw MappingException::tableIdGeneratorNotImplemented($className);
} else if ($customGeneratorAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\CustomIdGenerator')) {
$metadata->setCustomGeneratorDefinition(array(
'class' => $customGeneratorAnnot->class
));
}
} else if ($oneToOneAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToOne')) {
if ($idAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {

View File

@ -39,6 +39,7 @@ require_once __DIR__.'/../UniqueConstraint.php';
require_once __DIR__.'/../Index.php';
require_once __DIR__.'/../JoinTable.php';
require_once __DIR__.'/../SequenceGenerator.php';
require_once __DIR__.'/../CustomIdGenerator.php';
require_once __DIR__.'/../ChangeTrackingPolicy.php';
require_once __DIR__.'/../OrderBy.php';
require_once __DIR__.'/../NamedQueries.php';

View File

@ -259,6 +259,11 @@ class XmlDriver extends AbstractFileDriver
'allocationSize' => (string)$seqGenerator['allocation-size'],
'initialValue' => (string)$seqGenerator['initial-value']
));
} else if (isset($idElement->{'custom-id-generator'})) {
$customGenerator = $idElement->{'custom-id-generator'};
$metadata->setCustomGeneratorDefinition(array(
'class' => (string) $customGenerator['class']
));
} else if (isset($idElement->{'table-generator'})) {
throw MappingException::tableIdGeneratorNotImplemented($className);
}

View File

@ -200,6 +200,11 @@ class YamlDriver extends AbstractFileDriver
// Check for SequenceGenerator/TableGenerator definition
if (isset($idElement['sequenceGenerator'])) {
$metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']);
} else if (isset($idElement['customIdGenerator'])) {
$customGenerator = $idElement['customIdGenerator'];
$metadata->setCustomGeneratorDefinition(array(
'class' => (string) $customGenerator['class']
));
} else if (isset($idElement['tableGenerator'])) {
throw MappingException::tableIdGeneratorNotImplemented($className);
}

View File

@ -105,6 +105,18 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
);
}
public function testEntityCustomGenerator()
{
$class = $this->createClassMetadata('Doctrine\Tests\ORM\Mapping\Animal');
$this->assertEquals(ClassMetadata::GENERATOR_TYPE_CUSTOM,
$class->generatorType, "Generator Type");
$this->assertEquals(
array("class" => "stdClass"),
$class->customGeneratorDefinition,
"Custom Generator Definition");
}
/**
* @depends testEntityTableNameAndInheritance
@ -650,13 +662,15 @@ class User
abstract class Animal
{
/**
* @Id @Column(type="string") @GeneratedValue
* @Id @Column(type="string") @GeneratedValue(strategy="CUSTOM")
* @CustomIdGenerator(class="stdClass")
*/
public $id;
public static function loadMetadata(ClassMetadataInfo $metadata)
{
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_CUSTOM);
$metadata->setCustomGeneratorDefinition(array("class" => "stdClass"));
}
}

View File

@ -3,7 +3,6 @@
namespace Doctrine\Tests\ORM\Mapping;
use Doctrine\Tests\Mocks\MetadataDriverMock;
use Doctrine\Tests\Mocks\DatabasePlatformMock;
use Doctrine\Tests\Mocks\EntityManagerMock;
use Doctrine\Tests\Mocks\ConnectionMock;
use Doctrine\Tests\Mocks\DriverMock;
@ -25,28 +24,12 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$mockPlatform->setPrefersSequences(true);
$mockPlatform->setPrefersIdentityColumns(false);
// Self-made metadata
$cm1 = new ClassMetadata('Doctrine\Tests\ORM\Mapping\TestEntity1');
$cm1->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm1->setPrimaryTable(array('name' => '`group`'));
// Add a mapped field
$cm1->mapField(array('fieldName' => 'name', 'type' => 'varchar'));
// Add a mapped field
$cm1->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
// and a mapped association
$cm1->mapOneToOne(array('fieldName' => 'other', 'targetEntity' => 'TestEntity1', 'mappedBy' => 'this'));
// and an association on the owning side
$joinColumns = array(
array('name' => 'other_id', 'referencedColumnName' => 'id')
);
$cm1->mapOneToOne(array('fieldName' => 'association', 'targetEntity' => 'TestEntity1', 'joinColumns' => $joinColumns));
// and an id generator type
$cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);
$cm1 = $this->_createValidClassMetadata();
// SUT
$cmf = new \Doctrine\ORM\Mapping\ClassMetadataFactory();
$cmf->setEntityManager($entityManager);
$cmf->setMetadataFor('Doctrine\Tests\ORM\Mapping\TestEntity1', $cm1);
$cmf->setMetadataFor($cm1->name, $cm1);
// Prechecks
$this->assertEquals(array(), $cm1->parentClasses);
@ -57,7 +40,7 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('group', $cm1->table['name']);
// Go
$cmMap1 = $cmf->getMetadataFor('Doctrine\Tests\ORM\Mapping\TestEntity1');
$cmMap1 = $cmf->getMetadataFor($cm1->name);
$this->assertSame($cm1, $cmMap1);
$this->assertEquals('group', $cmMap1->table['name']);
@ -66,6 +49,46 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$this->assertTrue($cmMap1->hasField('name'));
}
public function testGetMetadataFor_ReturnsLoadedCustomIdGenerator()
{
$cm1 = $this->_createValidClassMetadata();
$cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_CUSTOM);
$cm1->customGeneratorDefinition = array(
"class" => "Doctrine\Tests\ORM\Mapping\CustomIdGenerator");
$cmf = $this->_createTestFactory();
$cmf->setMetadataForClass($cm1->name, $cm1);
$actual = $cmf->getMetadataFor($cm1->name);
$this->assertEquals(ClassMetadata::GENERATOR_TYPE_CUSTOM,
$actual->generatorType);
$this->assertInstanceOf("Doctrine\Tests\ORM\Mapping\CustomIdGenerator",
$actual->idGenerator);
}
public function testGetMetadataFor_ThrowsExceptionOnUnknownCustomGeneratorClass()
{
$cm1 = $this->_createValidClassMetadata();
$cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_CUSTOM);
$cm1->customGeneratorDefinition = array("class" => "NotExistingGenerator");
$cmf = $this->_createTestFactory();
$cmf->setMetadataForClass($cm1->name, $cm1);
$this->setExpectedException("Doctrine\ORM\ORMException");
$actual = $cmf->getMetadataFor($cm1->name);
}
public function testGetMetadataFor_ThrowsExceptionOnMissingCustomGeneratorDefinition()
{
$cm1 = $this->_createValidClassMetadata();
$cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_CUSTOM);
$cmf = $this->_createTestFactory();
$cmf->setMetadataForClass($cm1->name, $cm1);
$this->setExpectedException("Doctrine\ORM\ORMException");
$actual = $cmf->getMetadataFor($cm1->name);
}
public function testHasGetMetadata_NamespaceSeperatorIsNotNormalized()
{
require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php";
@ -143,6 +166,44 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
return EntityManagerMock::create($conn, $config, $eventManager);
}
/**
* @return ClassMetadataFactoryTestSubject
*/
protected function _createTestFactory()
{
$mockDriver = new MetadataDriverMock();
$entityManager = $this->_createEntityManager($mockDriver);
$cmf = new ClassMetadataFactoryTestSubject();
$cmf->setEntityManager($entityManager);
return $cmf;
}
/**
* @param string $class
* @return ClassMetadata
*/
protected function _createValidClassMetadata()
{
// Self-made metadata
$cm1 = new ClassMetadata('Doctrine\Tests\ORM\Mapping\TestEntity1');
$cm1->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm1->setPrimaryTable(array('name' => '`group`'));
// Add a mapped field
$cm1->mapField(array('fieldName' => 'name', 'type' => 'varchar'));
// Add a mapped field
$cm1->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
// and a mapped association
$cm1->mapOneToOne(array('fieldName' => 'other', 'targetEntity' => 'TestEntity1', 'mappedBy' => 'this'));
// and an association on the owning side
$joinColumns = array(
array('name' => 'other_id', 'referencedColumnName' => 'id')
);
$cm1->mapOneToOne(array('fieldName' => 'association', 'targetEntity' => 'TestEntity1', 'joinColumns' => $joinColumns));
// and an id generator type
$cm1->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);
return $cm1;
}
}
/* Test subject class with overriden factory method for mocking purposes */
@ -179,3 +240,10 @@ class TestEntity1
private $other;
private $association;
}
class CustomIdGenerator extends \Doctrine\ORM\Id\AbstractIdGenerator
{
public function generate(\Doctrine\ORM\EntityManager $em, $entity)
{
}
}

View File

@ -14,17 +14,14 @@ class PHPMappingDriverTest extends AbstractMappingDriverTest
{
$path = __DIR__ . DIRECTORY_SEPARATOR . 'php';
/*
// Convert YAML mapping information to PHP
// Uncomment this code if the YAML changes and you want to update the PHP code
// Convert Annotation mapping information to PHP
// Uncomment this code if annotations changed and you want to update the PHP code
// for the same mapping information
$cme = new ClassMetadataExporter();
$cme->addMappingSource(__DIR__ . DIRECTORY_SEPARATOR . 'yaml');
$exporter = $cme->getExporter('php', $path);
$exporter->setMetadatas($cme->getMetadatas());
$exporter->export();
*/
// $meta = new \Doctrine\ORM\Mapping\ClassMetadataInfo("Doctrine\Tests\ORM\Mapping\Animal");
// $driver = $this->createAnnotationDriver();
// $driver->loadMetadataForClass("Doctrine\Tests\ORM\Mapping\Animal", $meta);
// $exporter = $cme->getExporter('php', $path);
// echo $exporter->exportClassMetadata($meta);
return new PHPDriver($path);
}

View File

@ -0,0 +1,30 @@
<?php
use Doctrine\ORM\Mapping\ClassMetadataInfo;
/* @var $metadata ClassMetadataInfo */
$metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE);
$metadata->setDiscriminatorColumn(array(
'name' => 'dtype',
'type' => 'string',
'length' => 255,
'fieldName' => 'dtype',
));
$metadata->setDiscriminatorMap(array(
'cat' => 'Doctrine\\Tests\\ORM\\Mapping\\Cat',
'dog' => 'Doctrine\\Tests\\ORM\\Mapping\\Dog',
));
$metadata->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT);
$metadata->mapField(array(
'fieldName' => 'id',
'type' => 'string',
'length' => NULL,
'precision' => 0,
'scale' => 0,
'nullable' => false,
'unique' => false,
'id' => true,
'columnName' => 'id',
));
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_CUSTOM);
$metadata->setCustomGeneratorDefinition(array("class" => "stdClass"));

View File

@ -8,5 +8,9 @@
<discriminator-mapping value="cat" class="Cat" />
<discriminator-mapping value="dog" class="Dog" />
</discriminator-map>
<id name="id" type="integer" column="id">
<generator strategy="CUSTOM" />
<custom-id-generator class="stdClass" />
</id>
</entity>
</doctrine-mapping>

View File

@ -3,4 +3,11 @@ Doctrine\Tests\ORM\Mapping\Animal:
inheritanceType: SINGLE_TABLE
discriminatorMap:
cat: Cat
dog: Dog
dog: Dog
id:
id:
type: integer
generator:
strategy: CUSTOM
customIdGenerator:
class: stdClass

View File

@ -17,7 +17,7 @@ abstract class OrmTestCase extends DoctrineTestCase
/**
* @param array $paths
* @return \Doctrine\Common\Annotations\AnnotationReader
* @return \Doctrine\ORM\Mapping\Driver\AnnotationDriver
*/
protected function createAnnotationDriver($paths = array(), $alias = null)
{