Merge branch 'DDC-1723'
This commit is contained in:
commit
18e63f9cea
@ -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" />
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
30
lib/Doctrine/ORM/Mapping/CustomIdGenerator.php
Normal file
30
lib/Doctrine/ORM/Mapping/CustomIdGenerator.php
Normal 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;
|
||||
}
|
@ -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')) {
|
||||
|
@ -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';
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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"));
|
@ -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>
|
@ -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
|
@ -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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user