Merge branch 'master' of git://github.com/doctrine/doctrine2 into SupportCustomIdGenerators
This commit is contained in:
commit
78d3f647ff
92 changed files with 3299 additions and 280 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -12,4 +12,4 @@
|
|||
url = git://github.com/symfony/Yaml.git
|
||||
[submodule "lib/vendor/doctrine-build-common"]
|
||||
path = lib/vendor/doctrine-build-common
|
||||
url = https://github.com/doctrine/doctrine-build-common.git
|
||||
url = git://github.com/doctrine/doctrine-build-common.git
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"ext-pdo": "*",
|
||||
"doctrine/common": "master-dev",
|
||||
"doctrine/dbal": "master-dev"
|
||||
"doctrine/common": "dev-master",
|
||||
"doctrine/dbal": "dev-master"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "Doctrine\\ORM": "lib/" }
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
|
||||
<xs:complexType name="entity">
|
||||
<xs:sequence>
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:element name="indexes" type="orm:indexes" minOccurs="0"/>
|
||||
<xs:element name="unique-constraints" type="orm:unique-constraints" minOccurs="0"/>
|
||||
<xs:element name="discriminator-column" type="orm:discriminator-column" minOccurs="0"/>
|
||||
|
@ -110,6 +111,23 @@
|
|||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="option" mixed="true">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="option" type="orm:option"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required"/>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="options">
|
||||
<xs:sequence>
|
||||
<xs:element name="option" type="orm:option" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mapped-superclass" >
|
||||
<xs:complexContent>
|
||||
<xs:extension base="orm:entity">
|
||||
|
@ -165,6 +183,7 @@
|
|||
|
||||
<xs:complexType name="field">
|
||||
<xs:sequence>
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
|
@ -185,9 +204,10 @@
|
|||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="field-name" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="column-definition" type="xs:string" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
|
@ -261,6 +281,7 @@
|
|||
<xs:attribute name="type" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="column" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="association-key" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="column-definition" type="xs:string" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
|
@ -359,6 +380,7 @@
|
|||
<xs:attribute name="index-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
|
||||
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@ abstract class AbstractQuery
|
|||
{
|
||||
$key = trim($key, ':');
|
||||
|
||||
$value = $this->processParameterValue($value);
|
||||
if ($type === null) {
|
||||
$type = Query\ParameterTypeInferer::inferType($value);
|
||||
}
|
||||
|
@ -218,6 +219,53 @@ abstract class AbstractQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an individual parameter value
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
private function processParameterValue($value)
|
||||
{
|
||||
switch (true) {
|
||||
case is_array($value):
|
||||
for ($i = 0, $l = count($value); $i < $l; $i++) {
|
||||
$paramValue = $this->processParameterValue($value[$i]);
|
||||
$value[$i] = is_array($paramValue) ? $paramValue[key($paramValue)] : $paramValue;
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
||||
case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value)):
|
||||
return $this->convertObjectParameterToScalarValue($value);
|
||||
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
protected function convertObjectParameterToScalarValue($value)
|
||||
{
|
||||
$class = $this->_em->getClassMetadata(get_class($value));
|
||||
|
||||
if ($class->isIdentifierComposite) {
|
||||
throw new \InvalidArgumentException("Binding an entity with a composite primary key to a query is not supported. You should split the parameter into the explicit fields and bind them seperately.");
|
||||
}
|
||||
|
||||
if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) {
|
||||
$values = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
} else {
|
||||
$values = $class->getIdentifierValues($value);
|
||||
}
|
||||
|
||||
$value = $values[$class->getSingleIdentifierFieldName()];
|
||||
if (!$value) {
|
||||
throw new \InvalidArgumentException("Binding entities to query parameters only allowed for entities that have an identifier.");
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a collection of query parameters.
|
||||
*
|
||||
|
@ -316,7 +364,7 @@ abstract class AbstractQuery
|
|||
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||
? $this->_queryCacheProfile->setLifetime($lifetime)
|
||||
: new QueryCacheProfile($lifetime);
|
||||
: new QueryCacheProfile($lifetime, null, $this->_em->getConfiguration()->getResultCacheImpl());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -615,7 +663,7 @@ abstract class AbstractQuery
|
|||
{
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||
? $this->_queryCacheProfile->setCacheKey($id)
|
||||
: new QueryCacheProfile(0, $id);
|
||||
: new QueryCacheProfile(0, $id, $this->_em->getConfiguration()->getResultCacheImpl());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
@ -210,6 +210,7 @@ abstract class AbstractHydrator
|
|||
|
||||
case (isset($this->_rsm->scalarMappings[$key])):
|
||||
$cache[$key]['fieldName'] = $this->_rsm->scalarMappings[$key];
|
||||
$cache[$key]['type'] = Type::getType($this->_rsm->typeMappings[$key]);
|
||||
$cache[$key]['isScalar'] = true;
|
||||
break;
|
||||
|
||||
|
@ -232,6 +233,8 @@ abstract class AbstractHydrator
|
|||
}
|
||||
|
||||
if (isset($cache[$key]['isScalar'])) {
|
||||
$value = $cache[$key]['type']->convertToPHPValue($value, $this->_platform);
|
||||
|
||||
$rowData['scalars'][$cache[$key]['fieldName']] = $value;
|
||||
|
||||
continue;
|
||||
|
|
|
@ -286,4 +286,4 @@ class ArrayHydrator extends AbstractHydrator
|
|||
|
||||
return $this->_ce[$className];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,20 +234,7 @@ class ObjectHydrator extends AbstractHydrator
|
|||
|
||||
$this->_hints['fetchAlias'] = $dqlAlias;
|
||||
|
||||
$entity = $this->_uow->createEntity($className, $data, $this->_hints);
|
||||
|
||||
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
|
||||
if (isset($this->_ce[$className]->lifecycleCallbacks[Events::postLoad])) {
|
||||
$this->_ce[$className]->invokeLifecycleCallbacks(Events::postLoad, $entity);
|
||||
}
|
||||
|
||||
$evm = $this->_em->getEventManager();
|
||||
|
||||
if ($evm->hasListeners(Events::postLoad)) {
|
||||
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
|
||||
}
|
||||
|
||||
return $entity;
|
||||
return $this->_uow->createEntity($className, $data, $this->_hints);
|
||||
}
|
||||
|
||||
private function _getEntityFromIdentityMap($className, array $data)
|
||||
|
@ -359,7 +346,6 @@ class ObjectHydrator extends AbstractHydrator
|
|||
continue;
|
||||
}
|
||||
|
||||
|
||||
$parentClass = $this->_ce[$this->_rsm->aliasMap[$parentAlias]];
|
||||
$oid = spl_object_hash($parentObject);
|
||||
$relationField = $this->_rsm->relationMap[$dqlAlias];
|
||||
|
@ -368,6 +354,7 @@ class ObjectHydrator extends AbstractHydrator
|
|||
|
||||
// Check the type of the relation (many or single-valued)
|
||||
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
|
||||
$reflFieldValue = $reflField->getValue($parentObject);
|
||||
// PATH A: Collection-valued association
|
||||
if (isset($nonemptyComponents[$dqlAlias])) {
|
||||
$collKey = $oid . $relationField;
|
||||
|
@ -408,9 +395,12 @@ class ObjectHydrator extends AbstractHydrator
|
|||
// Update result pointer
|
||||
$this->_resultPointers[$dqlAlias] = $reflFieldValue[$index];
|
||||
}
|
||||
} else if ( ! $reflField->getValue($parentObject)) {
|
||||
} else if ( ! $reflFieldValue) {
|
||||
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
|
||||
} else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
|
||||
$reflFieldValue->setInitialized(true);
|
||||
}
|
||||
|
||||
} else {
|
||||
// PATH B: Single-valued association
|
||||
$reflFieldValue = $reflField->getValue($parentObject);
|
||||
|
|
|
@ -130,17 +130,6 @@ class SimpleObjectHydrator extends AbstractHydrator
|
|||
$uow = $this->_em->getUnitOfWork();
|
||||
$entity = $uow->createEntity($entityName, $data, $this->_hints);
|
||||
|
||||
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
|
||||
if (isset($this->class->lifecycleCallbacks[Events::postLoad])) {
|
||||
$this->class->invokeLifecycleCallbacks(Events::postLoad, $entity);
|
||||
}
|
||||
|
||||
$evm = $this->_em->getEventManager();
|
||||
|
||||
if ($evm->hasListeners(Events::postLoad)) {
|
||||
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
|
||||
}
|
||||
|
||||
$result[] = $entity;
|
||||
}
|
||||
|
||||
|
@ -191,4 +180,4 @@ class SimpleObjectHydrator extends AbstractHydrator
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -291,7 +291,6 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
|
|||
// Invoke driver
|
||||
try {
|
||||
$this->driver->loadMetadataForClass($className, $class);
|
||||
$this->wakeupReflection($class, $this->getReflectionService());
|
||||
} catch (ReflectionException $e) {
|
||||
throw MappingException::reflectionFailure($className, $e);
|
||||
}
|
||||
|
@ -333,6 +332,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
|
|||
$eventArgs = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($class, $this->em);
|
||||
$this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
|
||||
}
|
||||
$this->wakeupReflection($class, $this->getReflectionService());
|
||||
|
||||
$this->validateRuntimeMetadata($class, $parent);
|
||||
|
||||
|
|
|
@ -791,17 +791,18 @@ class ClassMetadataInfo implements ClassMetadata
|
|||
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
|
||||
* metadata of the class with the given name.
|
||||
*
|
||||
* @param string $entityName The name of the entity class the new instance is used for.
|
||||
* @param ReflectionService $reflService The reflection service.
|
||||
*/
|
||||
public function initializeReflection($reflService)
|
||||
{
|
||||
$this->reflClass = $reflService->getClass($this->name);
|
||||
$this->namespace = $reflService->getClassNamespace($this->name);
|
||||
$this->table['name'] = $this->namingStrategy->classToTableName($reflService->getClassShortName($this->name));
|
||||
|
||||
if ($this->reflClass) {
|
||||
$this->name = $this->rootEntityName = $this->reflClass->getName();
|
||||
}
|
||||
|
||||
$this->table['name'] = $this->namingStrategy->classToTableName($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1134,7 +1135,7 @@ class ClassMetadataInfo implements ClassMetadata
|
|||
$mapping['targetEntity'] = ltrim($mapping['targetEntity'], '\\');
|
||||
}
|
||||
|
||||
if ( ($mapping['type'] & (self::MANY_TO_ONE|self::MANY_TO_MANY)) > 0 &&
|
||||
if ( ($mapping['type'] & self::MANY_TO_ONE) > 0 &&
|
||||
isset($mapping['orphanRemoval']) &&
|
||||
$mapping['orphanRemoval'] == true) {
|
||||
|
||||
|
@ -1236,7 +1237,7 @@ class ClassMetadataInfo implements ClassMetadata
|
|||
|
||||
$uniqueContraintColumns = array();
|
||||
foreach ($mapping['joinColumns'] as $key => &$joinColumn) {
|
||||
if ($mapping['type'] === self::ONE_TO_ONE) {
|
||||
if ($mapping['type'] === self::ONE_TO_ONE && ! $this->isInheritanceTypeSingleTable()) {
|
||||
if (count($mapping['joinColumns']) == 1) {
|
||||
$joinColumn['unique'] = true;
|
||||
} else {
|
||||
|
@ -1354,6 +1355,8 @@ class ClassMetadataInfo implements ClassMetadata
|
|||
}
|
||||
}
|
||||
|
||||
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ? (bool) $mapping['orphanRemoval'] : false;
|
||||
|
||||
if (isset($mapping['orderBy'])) {
|
||||
if ( ! is_array($mapping['orderBy'])) {
|
||||
throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
|
||||
|
@ -1724,6 +1727,10 @@ class ClassMetadataInfo implements ClassMetadata
|
|||
if (isset($table['uniqueConstraints'])) {
|
||||
$this->table['uniqueConstraints'] = $table['uniqueConstraints'];
|
||||
}
|
||||
|
||||
if (isset($table['options'])) {
|
||||
$this->table['options'] = $table['options'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1952,19 +1959,22 @@ class ClassMetadataInfo implements ClassMetadata
|
|||
public function setDiscriminatorColumn($columnDef)
|
||||
{
|
||||
if ($columnDef !== null) {
|
||||
if ( ! isset($columnDef['name'])) {
|
||||
throw MappingException::nameIsMandatoryForDiscriminatorColumns($this->name);
|
||||
}
|
||||
|
||||
if (isset($this->fieldNames[$columnDef['name']])) {
|
||||
throw MappingException::duplicateColumnName($this->name, $columnDef['name']);
|
||||
}
|
||||
|
||||
if ( ! isset($columnDef['name'])) {
|
||||
throw MappingException::nameIsMandatoryForDiscriminatorColumns($this->name, $columnDef);
|
||||
}
|
||||
if ( ! isset($columnDef['fieldName'])) {
|
||||
$columnDef['fieldName'] = $columnDef['name'];
|
||||
}
|
||||
|
||||
if ( ! isset($columnDef['type'])) {
|
||||
$columnDef['type'] = "string";
|
||||
}
|
||||
|
||||
if (in_array($columnDef['type'], array("boolean", "array", "object", "datetime", "time", "date"))) {
|
||||
throw MappingException::invalidDiscriminatorColumnType($this->name, $columnDef['type']);
|
||||
}
|
||||
|
|
|
@ -33,4 +33,6 @@ final class DiscriminatorColumn implements Annotation
|
|||
public $length;
|
||||
/** @var mixed */
|
||||
public $fieldName; // field name used in non-object hydration (array/scalar)
|
||||
/** @var string */
|
||||
public $columnDefinition;
|
||||
}
|
||||
|
|
|
@ -134,6 +134,11 @@ class AnnotationDriver implements Driver
|
|||
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
|
||||
{
|
||||
$class = $metadata->getReflectionClass();
|
||||
if (!$class) {
|
||||
// this happens when running annotation driver in combination with
|
||||
// static reflection services. This is not the nicest fix
|
||||
$class = new \ReflectionClass($metadata->name);
|
||||
}
|
||||
|
||||
$classAnnotations = $this->_reader->getClassAnnotations($class);
|
||||
|
||||
|
@ -185,6 +190,10 @@ class AnnotationDriver implements Driver
|
|||
}
|
||||
}
|
||||
|
||||
if ($tableAnnot->options !== null) {
|
||||
$primaryTable['options'] = $tableAnnot->options;
|
||||
}
|
||||
|
||||
$metadata->setPrimaryTable($primaryTable);
|
||||
}
|
||||
|
||||
|
@ -219,7 +228,8 @@ class AnnotationDriver implements Driver
|
|||
$metadata->setDiscriminatorColumn(array(
|
||||
'name' => $discrColumnAnnot->name,
|
||||
'type' => $discrColumnAnnot->type,
|
||||
'length' => $discrColumnAnnot->length
|
||||
'length' => $discrColumnAnnot->length,
|
||||
'columnDefinition' => $discrColumnAnnot->columnDefinition
|
||||
));
|
||||
} else {
|
||||
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
|
||||
|
@ -406,6 +416,7 @@ class AnnotationDriver implements Driver
|
|||
$mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
|
||||
$mapping['cascade'] = $manyToManyAnnot->cascade;
|
||||
$mapping['indexBy'] = $manyToManyAnnot->indexBy;
|
||||
$mapping['orphanRemoval'] = $manyToManyAnnot->orphanRemoval;
|
||||
$mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch);
|
||||
|
||||
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
|
||||
|
|
|
@ -39,7 +39,34 @@ class DriverChain implements Driver
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $_drivers = array();
|
||||
private $drivers = array();
|
||||
|
||||
/**
|
||||
* The default driver
|
||||
*
|
||||
* @var Driver
|
||||
*/
|
||||
private $defaultDriver;
|
||||
|
||||
/**
|
||||
* Get the default driver.
|
||||
*
|
||||
* @return Driver
|
||||
*/
|
||||
public function getDefaultDriver()
|
||||
{
|
||||
return $this->defaultDriver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default driver.
|
||||
*
|
||||
* @param Driver $driver
|
||||
*/
|
||||
public function setDefaultDriver(Driver $driver)
|
||||
{
|
||||
$this->defaultDriver = $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a nested driver.
|
||||
|
@ -49,7 +76,7 @@ class DriverChain implements Driver
|
|||
*/
|
||||
public function addDriver(Driver $nestedDriver, $namespace)
|
||||
{
|
||||
$this->_drivers[$namespace] = $nestedDriver;
|
||||
$this->drivers[$namespace] = $nestedDriver;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,7 +86,7 @@ class DriverChain implements Driver
|
|||
*/
|
||||
public function getDrivers()
|
||||
{
|
||||
return $this->_drivers;
|
||||
return $this->drivers;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,13 +97,18 @@ class DriverChain implements Driver
|
|||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
|
||||
{
|
||||
foreach ($this->_drivers as $namespace => $driver) {
|
||||
foreach ($this->drivers as $namespace => $driver) {
|
||||
if (strpos($className, $namespace) === 0) {
|
||||
$driver->loadMetadataForClass($className, $metadata);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->defaultDriver !== null) {
|
||||
$this->defaultDriver->loadMetadataForClass($className, $metadata);
|
||||
return;
|
||||
}
|
||||
|
||||
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
|
||||
}
|
||||
|
||||
|
@ -89,7 +121,7 @@ class DriverChain implements Driver
|
|||
{
|
||||
$classNames = array();
|
||||
$driverClasses = array();
|
||||
foreach ($this->_drivers AS $namespace => $driver) {
|
||||
foreach ($this->drivers AS $namespace => $driver) {
|
||||
$oid = spl_object_hash($driver);
|
||||
if (!isset($driverClasses[$oid])) {
|
||||
$driverClasses[$oid] = $driver->getAllClassNames();
|
||||
|
@ -114,12 +146,16 @@ class DriverChain implements Driver
|
|||
*/
|
||||
public function isTransient($className)
|
||||
{
|
||||
foreach ($this->_drivers AS $namespace => $driver) {
|
||||
foreach ($this->drivers AS $namespace => $driver) {
|
||||
if (strpos($className, $namespace) === 0) {
|
||||
return $driver->isTransient($className);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->defaultDriver !== null) {
|
||||
return $this->defaultDriver->isTransient($className);
|
||||
}
|
||||
|
||||
// class isTransient, i.e. not an entity or mapped superclass
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -99,9 +99,10 @@ class XmlDriver extends AbstractFileDriver
|
|||
if (isset($xmlRoot->{'discriminator-column'})) {
|
||||
$discrColumn = $xmlRoot->{'discriminator-column'};
|
||||
$metadata->setDiscriminatorColumn(array(
|
||||
'name' => (string)$discrColumn['name'],
|
||||
'type' => (string)$discrColumn['type'],
|
||||
'length' => (string)$discrColumn['length']
|
||||
'name' => isset($discrColumn['name']) ? (string)$discrColumn['name'] : null,
|
||||
'type' => isset($discrColumn['type']) ? (string)$discrColumn['type'] : null,
|
||||
'length' => isset($discrColumn['length']) ? (string)$discrColumn['length'] : null,
|
||||
'columnDefinition' => isset($discrColumn['column-definition']) ? (string)$discrColumn['column-definition'] : null
|
||||
));
|
||||
} else {
|
||||
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
|
||||
|
@ -161,6 +162,10 @@ class XmlDriver extends AbstractFileDriver
|
|||
}
|
||||
}
|
||||
|
||||
if (isset($xmlRoot->options)) {
|
||||
$metadata->table['options'] = $this->_parseOptions($xmlRoot->options->children());
|
||||
}
|
||||
|
||||
// Evaluate <field ...> mappings
|
||||
if (isset($xmlRoot->field)) {
|
||||
foreach ($xmlRoot->field as $fieldMapping) {
|
||||
|
@ -192,10 +197,6 @@ class XmlDriver extends AbstractFileDriver
|
|||
$mapping['unique'] = ((string)$fieldMapping['unique'] == "false") ? false : true;
|
||||
}
|
||||
|
||||
if (isset($fieldMapping['options'])) {
|
||||
$mapping['options'] = (array)$fieldMapping['options'];
|
||||
}
|
||||
|
||||
if (isset($fieldMapping['nullable'])) {
|
||||
$mapping['nullable'] = ((string)$fieldMapping['nullable'] == "false") ? false : true;
|
||||
}
|
||||
|
@ -208,6 +209,10 @@ class XmlDriver extends AbstractFileDriver
|
|||
$mapping['columnDefinition'] = (string)$fieldMapping['column-definition'];
|
||||
}
|
||||
|
||||
if (isset($fieldMapping->options)) {
|
||||
$mapping['options'] = $this->_parseOptions($fieldMapping->options->children());
|
||||
}
|
||||
|
||||
$metadata->mapField($mapping);
|
||||
}
|
||||
}
|
||||
|
@ -402,6 +407,10 @@ class XmlDriver extends AbstractFileDriver
|
|||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$manyToManyElement['fetch']);
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['orphan-removal'])) {
|
||||
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphan-removal'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['mapped-by'])) {
|
||||
$mapping['mappedBy'] = (string)$manyToManyElement['mapped-by'];
|
||||
} else if (isset($manyToManyElement->{'join-table'})) {
|
||||
|
@ -459,6 +468,35 @@ class XmlDriver extends AbstractFileDriver
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses (nested) option elements.
|
||||
*
|
||||
* @param $options The XML element.
|
||||
* @return array The options array.
|
||||
*/
|
||||
private function _parseOptions(SimpleXMLElement $options)
|
||||
{
|
||||
$array = array();
|
||||
|
||||
foreach ($options as $option) {
|
||||
if ($option->count()) {
|
||||
$value = $this->_parseOptions($option->children());
|
||||
} else {
|
||||
$value = (string) $option;
|
||||
}
|
||||
|
||||
$attr = $option->attributes();
|
||||
|
||||
if (isset($attr->name)) {
|
||||
$array[(string) $attr->name] = $value;
|
||||
} else {
|
||||
$array[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a joinColumn mapping array based on the information
|
||||
* found in the given SimpleXMLElement.
|
||||
|
|
|
@ -96,9 +96,10 @@ class YamlDriver extends AbstractFileDriver
|
|||
if (isset($element['discriminatorColumn'])) {
|
||||
$discrColumn = $element['discriminatorColumn'];
|
||||
$metadata->setDiscriminatorColumn(array(
|
||||
'name' => $discrColumn['name'],
|
||||
'type' => $discrColumn['type'],
|
||||
'length' => $discrColumn['length']
|
||||
'name' => isset($discrColumn['name']) ? (string)$discrColumn['name'] : null,
|
||||
'type' => isset($discrColumn['type']) ? (string)$discrColumn['type'] : null,
|
||||
'length' => isset($discrColumn['length']) ? (string)$discrColumn['length'] : null,
|
||||
'columnDefinition' => isset($discrColumn['columnDefinition']) ? (string)$discrColumn['columnDefinition'] : null
|
||||
));
|
||||
} else {
|
||||
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
|
||||
|
@ -156,6 +157,10 @@ class YamlDriver extends AbstractFileDriver
|
|||
}
|
||||
}
|
||||
|
||||
if (isset($element['options'])) {
|
||||
$metadata->table['options'] = $element['options'];
|
||||
}
|
||||
|
||||
$associationIds = array();
|
||||
if (isset($element['id'])) {
|
||||
// Evaluate identifier settings
|
||||
|
@ -451,6 +456,10 @@ class YamlDriver extends AbstractFileDriver
|
|||
$mapping['indexBy'] = $manyToManyElement['indexBy'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['orphanRemoval'])) {
|
||||
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval'];
|
||||
}
|
||||
|
||||
$metadata->mapManyToMany($mapping);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ final class ManyToMany implements Annotation
|
|||
public $cascade;
|
||||
/** @var string */
|
||||
public $fetch = 'LAZY';
|
||||
/** @var boolean */
|
||||
public $orphanRemoval = false;
|
||||
/** @var string */
|
||||
public $indexBy;
|
||||
}
|
||||
|
|
|
@ -226,6 +226,11 @@ class MappingException extends \Doctrine\ORM\ORMException
|
|||
return new self("Discriminator column type on entity class '$className' is not allowed to be '$type'. 'string' or 'integer' type variables are suggested!");
|
||||
}
|
||||
|
||||
public static function nameIsMandatoryForDiscriminatorColumns($className)
|
||||
{
|
||||
return new self("Discriminator column name on entity class '$className' is not defined.");
|
||||
}
|
||||
|
||||
public static function cannotVersionIdField($className, $fieldName)
|
||||
{
|
||||
return new self("Setting Id field '$fieldName' as versionale in entity class '$className' is not supported.");
|
||||
|
|
|
@ -33,4 +33,6 @@ final class Table implements Annotation
|
|||
public $indexes;
|
||||
/** @var array<\Doctrine\ORM\Mapping\UniqueConstraint> */
|
||||
public $uniqueConstraints;
|
||||
/** @var array */
|
||||
public $options = array();
|
||||
}
|
||||
|
|
|
@ -305,6 +305,7 @@ final class PersistentCollection implements Collection
|
|||
if ($this->association !== null &&
|
||||
$this->association['isOwningSide'] &&
|
||||
$this->association['type'] === ClassMetadata::MANY_TO_MANY &&
|
||||
$this->owner &&
|
||||
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
|
||||
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
|
||||
}
|
||||
|
@ -387,7 +388,7 @@ final class PersistentCollection implements Collection
|
|||
$this->changed();
|
||||
|
||||
if ($this->association !== null &&
|
||||
$this->association['type'] == ClassMetadata::ONE_TO_MANY &&
|
||||
$this->association['type'] & ClassMetadata::TO_MANY &&
|
||||
$this->association['orphanRemoval']) {
|
||||
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
|
||||
}
|
||||
|
@ -425,7 +426,7 @@ final class PersistentCollection implements Collection
|
|||
$this->changed();
|
||||
|
||||
if ($this->association !== null &&
|
||||
$this->association['type'] === ClassMetadata::ONE_TO_MANY &&
|
||||
$this->association['type'] & ClassMetadata::TO_MANY &&
|
||||
$this->association['orphanRemoval']) {
|
||||
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
|
||||
}
|
||||
|
@ -630,7 +631,7 @@ final class PersistentCollection implements Collection
|
|||
|
||||
$uow = $this->em->getUnitOfWork();
|
||||
|
||||
if ($this->association['type'] === ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
|
||||
if ($this->association['type'] & ClassMetadata::TO_MANY && $this->association['orphanRemoval']) {
|
||||
// we need to initialize here, as orphan removal acts like implicit cascadeRemove,
|
||||
// hence for event listeners we need the objects in memory.
|
||||
$this->initialize();
|
||||
|
@ -759,4 +760,27 @@ final class PersistentCollection implements Collection
|
|||
|
||||
return $this->coll->slice($offset, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup internal state of cloned persistent collection.
|
||||
*
|
||||
* The following problems have to be prevented:
|
||||
* 1. Added entities are added to old PC
|
||||
* 2. New collection is not dirty, if reused on other entity nothing
|
||||
* changes.
|
||||
* 3. Snapshot leads to invalid diffs being generated.
|
||||
* 4. Lazy loading grabs entities from old owner object.
|
||||
* 5. New collection is connected to old owner and leads to duplicate keys.
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->initialize();
|
||||
$this->owner = null;
|
||||
|
||||
if (is_object($this->coll)) {
|
||||
$this->coll = clone $this->coll;
|
||||
}
|
||||
$this->snapshot = array();
|
||||
$this->changed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,4 +204,4 @@ abstract class AbstractCollectionPersister
|
|||
* @param mixed $element
|
||||
*/
|
||||
abstract protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -698,16 +698,6 @@ class BasicEntityPersister
|
|||
|
||||
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
|
||||
$hydrator->hydrateAll($stmt, $this->_rsm, array(Query::HINT_REFRESH => true));
|
||||
|
||||
if (isset($this->_class->lifecycleCallbacks[Events::postLoad])) {
|
||||
$this->_class->invokeLifecycleCallbacks(Events::postLoad, $entity);
|
||||
}
|
||||
|
||||
$evm = $this->_em->getEventManager();
|
||||
|
||||
if ($evm->hasListeners(Events::postLoad)) {
|
||||
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1152,9 +1142,10 @@ class BasicEntityPersister
|
|||
foreach ($columns AS $column) {
|
||||
$placeholder = '?';
|
||||
|
||||
if (isset($this->_columnTypes[$column]) &&
|
||||
if (isset($this->_class->fieldNames[$column]) &&
|
||||
isset($this->_columnTypes[$this->_class->fieldNames[$column]]) &&
|
||||
isset($this->_class->fieldMappings[$this->_class->fieldNames[$column]]['requireSQLConversion'])) {
|
||||
$type = Type::getType($this->_columnTypes[$column]);
|
||||
$type = Type::getType($this->_columnTypes[$this->_class->fieldNames[$column]]);
|
||||
$placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform);
|
||||
}
|
||||
|
||||
|
|
|
@ -253,8 +253,15 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||
{
|
||||
$uow = $this->_em->getUnitOfWork();
|
||||
|
||||
// shortcut for new entities
|
||||
if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
|
||||
// Shortcut for new entities
|
||||
$entityState = $uow->getEntityState($element, UnitOfWork::STATE_NEW);
|
||||
|
||||
if ($entityState === UnitOfWork::STATE_NEW) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Entity is scheduled for inclusion
|
||||
if ($entityState === UnitOfWork::STATE_MANAGED && $uow->isScheduledForInsert($element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -275,7 +282,15 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||
$uow = $this->_em->getUnitOfWork();
|
||||
|
||||
// shortcut for new entities
|
||||
if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
|
||||
$entityState = $uow->getEntityState($element, UnitOfWork::STATE_NEW);
|
||||
|
||||
if ($entityState === UnitOfWork::STATE_NEW) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If Entity is scheduled for inclusion, it is not in this collection.
|
||||
// We can assure that because it would have return true before on array check
|
||||
if ($entityState === UnitOfWork::STATE_MANAGED && $uow->isScheduledForInsert($element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,14 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||
$uow = $this->_em->getUnitOfWork();
|
||||
|
||||
// shortcut for new entities
|
||||
if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
|
||||
$entityState = $uow->getEntityState($element, UnitOfWork::STATE_NEW);
|
||||
|
||||
if ($entityState === UnitOfWork::STATE_NEW) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Entity is scheduled for inclusion
|
||||
if ($entityState === UnitOfWork::STATE_MANAGED && $uow->isScheduledForInsert($element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -168,7 +175,7 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||
// only works with single id identifier entities. Will throw an
|
||||
// exception in Entity Persisters if that is not the case for the
|
||||
// 'mappedBy' field.
|
||||
$id = current( $uow->getEntityIdentifier($coll->getOwner()) );
|
||||
$id = current( $uow->getEntityIdentifier($coll->getOwner()));
|
||||
|
||||
return $persister->exists($element, array($mapping['mappedBy'] => $id));
|
||||
}
|
||||
|
@ -183,7 +190,15 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||
$uow = $this->_em->getUnitOfWork();
|
||||
|
||||
// shortcut for new entities
|
||||
if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
|
||||
$entityState = $uow->getEntityState($element, UnitOfWork::STATE_NEW);
|
||||
|
||||
if ($entityState === UnitOfWork::STATE_NEW) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If Entity is scheduled for inclusion, it is not in this collection.
|
||||
// We can assure that because it would have return true before on array check
|
||||
if ($entityState === UnitOfWork::STATE_MANAGED && $uow->isScheduledForInsert($element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,12 +48,13 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
|||
|
||||
$columnList = parent::_getSelectColumnListSQL();
|
||||
|
||||
// Append discriminator column
|
||||
$discrColumn = $this->_class->discriminatorColumn['name'];
|
||||
$columnList .= ', ' . $discrColumn;
|
||||
|
||||
$rootClass = $this->_em->getClassMetadata($this->_class->rootEntityName);
|
||||
$tableAlias = $this->_getSQLTableAlias($rootClass->name);
|
||||
|
||||
// Append discriminator column
|
||||
$discrColumn = $this->_class->discriminatorColumn['name'];
|
||||
$columnList .= ', ' . $tableAlias . '.' . $discrColumn;
|
||||
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($discrColumn);
|
||||
|
||||
$this->_rsm->setDiscriminatorColumn('r', $resultColumnName);
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* 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
|
||||
|
@ -21,10 +19,12 @@
|
|||
|
||||
namespace Doctrine\ORM\Proxy;
|
||||
|
||||
use Doctrine\Common\Persistence\Proxy as BaseProxy;
|
||||
|
||||
/**
|
||||
* Interface for proxy classes.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
*/
|
||||
interface Proxy {}
|
||||
interface Proxy extends BaseProxy {}
|
||||
|
|
|
@ -36,6 +36,10 @@ class ProxyException extends \Doctrine\ORM\ORMException {
|
|||
return new self("You must configure a proxy directory. See docs for details");
|
||||
}
|
||||
|
||||
public static function proxyDirectoryNotWritable() {
|
||||
return new self("Your proxy directory must be writable.");
|
||||
}
|
||||
|
||||
public static function proxyNamespaceRequired() {
|
||||
return new self("You must configure a proxy namespace. See docs for details");
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ namespace Doctrine\ORM\Proxy;
|
|||
|
||||
use Doctrine\ORM\EntityManager,
|
||||
Doctrine\ORM\Mapping\ClassMetadata,
|
||||
Doctrine\ORM\Mapping\AssociationMapping;
|
||||
Doctrine\ORM\Mapping\AssociationMapping,
|
||||
Doctrine\Common\Util\ClassUtils;
|
||||
|
||||
/**
|
||||
* This factory is used to create proxy objects for entities at runtime.
|
||||
|
@ -41,6 +42,14 @@ class ProxyFactory
|
|||
/** The directory that contains all proxy classes. */
|
||||
private $_proxyDir;
|
||||
|
||||
/**
|
||||
* Used to match very simple id methods that don't need
|
||||
* to be proxied since the identifier is known.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PATTERN_MATCH_ID_METHOD = '((public\s)?(function\s{1,}%s\s?\(\)\s{1,})\s{0,}{\s{0,}return\s{0,}\$this->%s;\s{0,}})i';
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the <tt>ProxyFactory</tt> class that is
|
||||
* connected to the given <tt>EntityManager</tt>.
|
||||
|
@ -74,13 +83,12 @@ class ProxyFactory
|
|||
*/
|
||||
public function getProxy($className, $identifier)
|
||||
{
|
||||
$proxyClassName = str_replace('\\', '', $className) . 'Proxy';
|
||||
$fqn = $this->_proxyNamespace . '\\' . $proxyClassName;
|
||||
$fqn = ClassUtils::generateProxyClassName($className, $this->_proxyNamespace);
|
||||
|
||||
if (! class_exists($fqn, false)) {
|
||||
$fileName = $this->_proxyDir . DIRECTORY_SEPARATOR . $proxyClassName . '.php';
|
||||
$fileName = $this->getProxyFileName($className);
|
||||
if ($this->_autoGenerate) {
|
||||
$this->_generateProxyClass($this->_em->getClassMetadata($className), $proxyClassName, $fileName, self::$_proxyClassTemplate);
|
||||
$this->_generateProxyClass($this->_em->getClassMetadata($className), $fileName, self::$_proxyClassTemplate);
|
||||
}
|
||||
require $fileName;
|
||||
}
|
||||
|
@ -94,6 +102,17 @@ class ProxyFactory
|
|||
return new $fqn($entityPersister, $identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the Proxy file name
|
||||
*
|
||||
* @param string $className
|
||||
* @return string
|
||||
*/
|
||||
private function getProxyFileName($className)
|
||||
{
|
||||
return $this->_proxyDir . DIRECTORY_SEPARATOR . '__CG__' . str_replace('\\', '', $className) . '.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates proxy classes for all given classes.
|
||||
*
|
||||
|
@ -112,21 +131,19 @@ class ProxyFactory
|
|||
continue;
|
||||
}
|
||||
|
||||
$proxyClassName = str_replace('\\', '', $class->name) . 'Proxy';
|
||||
$proxyFileName = $proxyDir . $proxyClassName . '.php';
|
||||
$this->_generateProxyClass($class, $proxyClassName, $proxyFileName, self::$_proxyClassTemplate);
|
||||
$proxyFileName = $this->getProxyFileName($class->name);
|
||||
$this->_generateProxyClass($class, $proxyFileName, self::$_proxyClassTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a proxy class file.
|
||||
*
|
||||
* @param $class
|
||||
* @param $originalClassName
|
||||
* @param $proxyClassName
|
||||
* @param $file The path of the file to write to.
|
||||
* @param ClassMetadata $class Metadata for the original class
|
||||
* @param string $fileName Filename (full path) for the generated class
|
||||
* @param string $file The proxy class template data
|
||||
*/
|
||||
private function _generateProxyClass($class, $proxyClassName, $fileName, $file)
|
||||
private function _generateProxyClass(ClassMetadata $class, $fileName, $file)
|
||||
{
|
||||
$methods = $this->_generateMethods($class);
|
||||
$sleepImpl = $this->_generateSleep($class);
|
||||
|
@ -138,20 +155,33 @@ class ProxyFactory
|
|||
'<methods>', '<sleepImpl>', '<cloneImpl>'
|
||||
);
|
||||
|
||||
if(substr($class->name, 0, 1) == "\\") {
|
||||
$className = substr($class->name, 1);
|
||||
} else {
|
||||
$className = $class->name;
|
||||
}
|
||||
$className = ltrim($class->name, '\\');
|
||||
$proxyClassName = ClassUtils::generateProxyClassName($class->name, $this->_proxyNamespace);
|
||||
$parts = explode('\\', strrev($proxyClassName), 2);
|
||||
$proxyClassNamespace = strrev($parts[1]);
|
||||
$proxyClassName = strrev($parts[0]);
|
||||
|
||||
$replacements = array(
|
||||
$this->_proxyNamespace,
|
||||
$proxyClassName, $className,
|
||||
$methods, $sleepImpl, $cloneImpl
|
||||
$proxyClassNamespace,
|
||||
$proxyClassName,
|
||||
$className,
|
||||
$methods,
|
||||
$sleepImpl,
|
||||
$cloneImpl
|
||||
);
|
||||
|
||||
$file = str_replace($placeholders, $replacements, $file);
|
||||
|
||||
$parentDirectory = dirname($fileName);
|
||||
|
||||
if ( ! is_dir($parentDirectory)) {
|
||||
if (false === @mkdir($parentDirectory, 0775, true)) {
|
||||
throw ProxyException::proxyDirectoryNotWritable();
|
||||
}
|
||||
} else if ( ! is_writable($parentDirectory)) {
|
||||
throw ProxyException::proxyDirectoryNotWritable();
|
||||
}
|
||||
|
||||
file_put_contents($fileName, $file, LOCK_EX);
|
||||
}
|
||||
|
||||
|
@ -230,14 +260,22 @@ class ProxyFactory
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if the method is a short identifier getter.
|
||||
*
|
||||
* What does this mean? For proxy objects the identifier is already known,
|
||||
* however accessing the getter for this identifier usually triggers the
|
||||
* lazy loading, leading to a query that may not be necessary if only the
|
||||
* ID is interesting for the userland code (for example in views that
|
||||
* generate links to the entity, but do not display anything else).
|
||||
*
|
||||
* @param ReflectionMethod $method
|
||||
* @param ClassMetadata $class
|
||||
* @return bool
|
||||
*/
|
||||
private function isShortIdentifierGetter($method, $class)
|
||||
private function isShortIdentifierGetter($method, ClassMetadata $class)
|
||||
{
|
||||
$identifier = lcfirst(substr($method->getName(), 3));
|
||||
return (
|
||||
$cheapCheck = (
|
||||
$method->getNumberOfParameters() == 0 &&
|
||||
substr($method->getName(), 0, 3) == "get" &&
|
||||
in_array($identifier, $class->identifier, true) &&
|
||||
|
@ -245,6 +283,18 @@ class ProxyFactory
|
|||
(($method->getEndLine() - $method->getStartLine()) <= 4)
|
||||
&& in_array($class->fieldMappings[$identifier]['type'], array('integer', 'bigint', 'smallint', 'string'))
|
||||
);
|
||||
|
||||
if ($cheapCheck) {
|
||||
$code = file($method->getDeclaringClass()->getFileName());
|
||||
$code = trim(implode(" ", array_slice($code, $method->getStartLine() - 1, $method->getEndLine() - $method->getStartLine() + 1)));
|
||||
|
||||
$pattern = sprintf(self::PATTERN_MATCH_ID_METHOD, $method->getName(), $identifier);
|
||||
|
||||
if (preg_match($pattern, $code)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -318,6 +368,12 @@ class <proxyClassName> extends \<className> implements \Doctrine\ORM\Proxy\Proxy
|
|||
}
|
||||
}
|
||||
|
||||
/** @private */
|
||||
public function __isInitialized()
|
||||
{
|
||||
return $this->__isInitialized__;
|
||||
}
|
||||
|
||||
<methods>
|
||||
|
||||
public function __sleep()
|
||||
|
|
|
@ -282,7 +282,8 @@ final class Query extends AbstractQuery
|
|||
}
|
||||
|
||||
$sqlPositions = $paramMappings[$key];
|
||||
$value = array_values($this->processParameterValue($value));
|
||||
// optimized multi value sql positions away for now, they are not allowed in DQL anyways.
|
||||
$value = array($value);
|
||||
$countValue = count($value);
|
||||
|
||||
for ($i = 0, $l = count($sqlPositions); $i < $l; $i++) {
|
||||
|
@ -305,39 +306,6 @@ final class Query extends AbstractQuery
|
|||
return array($sqlParams, $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an individual parameter value
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
private function processParameterValue($value)
|
||||
{
|
||||
switch (true) {
|
||||
case is_array($value):
|
||||
for ($i = 0, $l = count($value); $i < $l; $i++) {
|
||||
$paramValue = $this->processParameterValue($value[$i]);
|
||||
|
||||
// TODO: What about Entities that have composite primary key?
|
||||
$value[$i] = is_array($paramValue) ? $paramValue[key($paramValue)] : $paramValue;
|
||||
}
|
||||
|
||||
return array($value);
|
||||
|
||||
case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value)):
|
||||
if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) {
|
||||
return array_values($this->_em->getUnitOfWork()->getEntityIdentifier($value));
|
||||
}
|
||||
|
||||
$class = $this->_em->getClassMetadata(get_class($value));
|
||||
|
||||
return array_values($class->getIdentifierValues($value));
|
||||
|
||||
default:
|
||||
return array($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a cache driver to be used for caching queries.
|
||||
*
|
||||
|
|
|
@ -71,6 +71,12 @@ class ResultSetMapping
|
|||
*/
|
||||
public $scalarMappings = array();
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @var array Maps column names in the result set to the alias/field type to use in the mapped result.
|
||||
*/
|
||||
public $typeMappings = array();
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @var array Maps entities in the result set to the alias name to use in the mapped result.
|
||||
|
@ -296,12 +302,16 @@ class ResultSetMapping
|
|||
*
|
||||
* @param string $columnName The name of the column in the SQL result set.
|
||||
* @param string $alias The result alias with which the scalar result should be placed in the result structure.
|
||||
* @param string $type The column type
|
||||
*
|
||||
* @return ResultSetMapping This ResultSetMapping instance.
|
||||
*
|
||||
* @todo Rename: addScalar
|
||||
*/
|
||||
public function addScalarResult($columnName, $alias)
|
||||
public function addScalarResult($columnName, $alias, $type = 'string')
|
||||
{
|
||||
$this->scalarMappings[$columnName] = $alias;
|
||||
$this->typeMappings[$columnName] = $type;
|
||||
|
||||
if ( ! $this->isMixed && $this->fieldMappings) {
|
||||
$this->isMixed = true;
|
||||
|
|
|
@ -39,6 +39,11 @@ use Doctrine\DBAL\LockMode,
|
|||
*/
|
||||
class SqlWalker implements TreeWalker
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const HINT_DISTINCT = 'doctrine.distinct';
|
||||
|
||||
/**
|
||||
* @var ResultSetMapping
|
||||
*/
|
||||
|
@ -590,6 +595,10 @@ class SqlWalker implements TreeWalker
|
|||
$sql = 'SELECT ' . (($selectClause->isDistinct) ? 'DISTINCT ' : '');
|
||||
$sqlSelectExpressions = array_filter(array_map(array($this, 'walkSelectExpression'), $selectClause->selectExpressions));
|
||||
|
||||
if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true && $selectClause->isDistinct) {
|
||||
$this->_query->setHint(self::HINT_DISTINCT, true);
|
||||
}
|
||||
|
||||
$addMetaColumns = ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD) &&
|
||||
$this->_query->getHydrationMode() == Query::HYDRATE_OBJECT
|
||||
||
|
||||
|
@ -627,11 +636,17 @@ class SqlWalker implements TreeWalker
|
|||
}
|
||||
|
||||
// Add foreign key columns to SQL, if necessary
|
||||
if ( ! $addMetaColumns) continue;
|
||||
if ( ! $addMetaColumns && ! $class->containsForeignIdentifier) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add foreign key columns of class and also parent classes
|
||||
foreach ($class->associationMappings as $assoc) {
|
||||
if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) continue;
|
||||
if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) {
|
||||
continue;
|
||||
} else if ( !$addMetaColumns && !isset($assoc['id'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$owningClass = (isset($assoc['inherited'])) ? $this->_em->getClassMetadata($assoc['inherited']) : $class;
|
||||
$sqlTableAlias = $this->getSQLTableAlias($owningClass->getTableName(), $dqlAlias);
|
||||
|
@ -645,6 +660,11 @@ class SqlWalker implements TreeWalker
|
|||
}
|
||||
}
|
||||
|
||||
// Add foreign key columns to SQL, if necessary
|
||||
if ( ! $addMetaColumns) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add foreign key columns of subclasses
|
||||
foreach ($class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
|
@ -811,9 +831,10 @@ class SqlWalker implements TreeWalker
|
|||
|
||||
// Ensure we got the owning side, since it has all mapping info
|
||||
$assoc = ( ! $relation['isOwningSide']) ? $targetClass->associationMappings[$relation['mappedBy']] : $relation;
|
||||
|
||||
if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true && $relation['type'] & ClassMetadata::TO_MANY) {
|
||||
throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
|
||||
if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true && (!$this->_query->getHint(self::HINT_DISTINCT) || isset($this->_selectedClasses[$joinedDqlAlias]))) {
|
||||
if ($relation['type'] == ClassMetadata::ONE_TO_MANY || $relation['type'] == ClassMetadata::MANY_TO_MANY) {
|
||||
throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
|
||||
}
|
||||
}
|
||||
|
||||
if ($joinVarDecl->indexBy) {
|
||||
|
@ -1084,8 +1105,10 @@ class SqlWalker implements TreeWalker
|
|||
|
||||
$col = $sqlTableAlias . '.' . $columnName;
|
||||
|
||||
$fieldType = $class->getTypeOfField($fieldName);
|
||||
|
||||
if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) {
|
||||
$type = Type::getType($class->getTypeOfField($fieldName));
|
||||
$type = Type::getType($fieldType);
|
||||
$col = $type->convertToPHPValueSQL($col, $this->_conn->getDatabasePlatform());
|
||||
}
|
||||
|
||||
|
@ -1094,7 +1117,7 @@ class SqlWalker implements TreeWalker
|
|||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias, $fieldType);
|
||||
$this->_scalarFields[$dqlAlias][$fieldName] = $columnAlias;
|
||||
}
|
||||
break;
|
||||
|
@ -1118,7 +1141,8 @@ class SqlWalker implements TreeWalker
|
|||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
// We cannot resolve field type here; assume 'string'.
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias, 'string');
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1131,7 +1155,8 @@ class SqlWalker implements TreeWalker
|
|||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||
|
||||
if ( ! $hidden) {
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||
// We cannot resolve field type here; assume 'string'.
|
||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias, 'string');
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ class QueryBuilder
|
|||
* @var array The array of DQL parts collected.
|
||||
*/
|
||||
private $_dqlParts = array(
|
||||
'distinct' => false,
|
||||
'select' => array(),
|
||||
'from' => array(),
|
||||
'join' => array(),
|
||||
|
@ -346,7 +347,7 @@ class QueryBuilder
|
|||
* ->setParameters(array(
|
||||
* 'user_id1' => 1,
|
||||
* 'user_id2' => 2
|
||||
* ));
|
||||
));
|
||||
* </code>
|
||||
*
|
||||
* @param array $params The query parameters to set.
|
||||
|
@ -503,6 +504,25 @@ class QueryBuilder
|
|||
return $this->add('select', new Expr\Select($selects), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a DISTINCT flag to this query.
|
||||
*
|
||||
* <code>
|
||||
* $qb = $em->createQueryBuilder()
|
||||
* ->select('u')
|
||||
* ->distinct()
|
||||
* ->from('User', 'u');
|
||||
* </code>
|
||||
*
|
||||
* @param bool
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function distinct($flag = true)
|
||||
{
|
||||
$this->_dqlParts['distinct'] = (bool) $flag;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an item that is to be returned in the query result.
|
||||
*
|
||||
|
@ -981,7 +1001,9 @@ class QueryBuilder
|
|||
|
||||
private function _getDQLForSelect()
|
||||
{
|
||||
$dql = 'SELECT' . $this->_getReducedDQLQueryPart('select', array('pre' => ' ', 'separator' => ', '));
|
||||
$dql = 'SELECT'
|
||||
. ($this->_dqlParts['distinct']===true ? ' DISTINCT' : '')
|
||||
. $this->_getReducedDQLQueryPart('select', array('pre' => ' ', 'separator' => ', '));
|
||||
|
||||
$fromParts = $this->getDQLPart('from');
|
||||
$joinParts = $this->getDQLPart('join');
|
||||
|
@ -1090,4 +1112,4 @@ class QueryBuilder
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,14 +28,16 @@ class ConsoleRunner
|
|||
* Run console with the given helperset.
|
||||
*
|
||||
* @param \Symfony\Component\Console\Helper\HelperSet $helperSet
|
||||
* @param \Symfony\Component\Console\Command\Command[] $commands
|
||||
* @return void
|
||||
*/
|
||||
static public function run(HelperSet $helperSet)
|
||||
static public function run(HelperSet $helperSet, $commands = array())
|
||||
{
|
||||
$cli = new Application('Doctrine Command Line Interface', \Doctrine\ORM\Version::VERSION);
|
||||
$cli->setCatchExceptions(true);
|
||||
$cli->setHelperSet($helperSet);
|
||||
self::addCommands($cli);
|
||||
$cli->addCommands($commands);
|
||||
$cli->run();
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,15 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo,
|
|||
*/
|
||||
class EntityGenerator
|
||||
{
|
||||
/**
|
||||
* Specifies class fields should be protected
|
||||
*/
|
||||
const FIELD_VISIBLE_PROTECTED = 'protected';
|
||||
/**
|
||||
* Specifies class fields should be private
|
||||
*/
|
||||
const FIELD_VISIBLE_PRIVATE = 'private';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
@ -86,6 +95,8 @@ class EntityGenerator
|
|||
/** Whether or not to re-generate entity class if it exists already */
|
||||
private $_regenerateEntityIfExists = false;
|
||||
|
||||
private $_fieldVisibility = 'private';
|
||||
|
||||
private static $_classTemplate =
|
||||
'<?php
|
||||
|
||||
|
@ -128,10 +139,12 @@ public function <methodName>(<methodTypeHint>$<variableName><variableDefault>)
|
|||
* <description>
|
||||
*
|
||||
* @param <variableType>$<variableName>
|
||||
* @return <entity>
|
||||
*/
|
||||
public function <methodName>(<methodTypeHint>$<variableName>)
|
||||
{
|
||||
<spaces>$this-><fieldName>[] = $<variableName>;
|
||||
<spaces>return $this;
|
||||
}';
|
||||
|
||||
private static $_lifecycleCallbackMethodTemplate =
|
||||
|
@ -191,6 +204,8 @@ public function <methodName>()
|
|||
|
||||
if ( ! $this->_isNew) {
|
||||
$this->_parseTokensInEntityFile(file_get_contents($path));
|
||||
} else {
|
||||
$this->_staticReflection[$metadata->name] = array('properties' => array(), 'methods' => array());
|
||||
}
|
||||
|
||||
if ($this->_backupExisting && file_exists($path)) {
|
||||
|
@ -297,6 +312,21 @@ public function <methodName>()
|
|||
$this->_generateAnnotations = $bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class fields visibility for the entity (can either be private or protected)
|
||||
*
|
||||
* @param bool $bool
|
||||
* @return void
|
||||
*/
|
||||
public function setFieldVisibility($visibility)
|
||||
{
|
||||
if ($visibility !== self::FIELD_VISIBLE_PRIVATE && $visibility !== self::FIELD_VISIBLE_PROTECTED) {
|
||||
throw new \InvalidArgumentException('Invalid provided visibilty (only private and protected are allowed): ' . $visibility);
|
||||
}
|
||||
|
||||
$this->_fieldVisibility = $visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an annotation prefix.
|
||||
*
|
||||
|
@ -581,9 +611,32 @@ public function <methodName>()
|
|||
$table[] = 'name="' . $metadata->table['name'] . '"';
|
||||
}
|
||||
|
||||
if (isset($metadata->table['uniqueConstraints']) && $metadata->table['uniqueConstraints']) {
|
||||
$constraints = $this->_generateTableConstraints('UniqueConstraint', $metadata->table['uniqueConstraints']);
|
||||
$table[] = 'uniqueConstraints={' . $constraints . '}';
|
||||
}
|
||||
|
||||
if (isset($metadata->table['indexes']) && $metadata->table['indexes']) {
|
||||
$constraints = $this->_generateTableConstraints('Index', $metadata->table['indexes']);
|
||||
$table[] = 'indexes={' . $constraints . '}';
|
||||
}
|
||||
|
||||
return '@' . $this->_annotationsPrefix . 'Table(' . implode(', ', $table) . ')';
|
||||
}
|
||||
|
||||
private function _generateTableConstraints($constraintName, $constraints)
|
||||
{
|
||||
$annotations = array();
|
||||
foreach ($constraints as $name => $constraint) {
|
||||
$columns = array();
|
||||
foreach ($constraint['columns'] as $column) {
|
||||
$columns[] = '"' . $column . '"';
|
||||
}
|
||||
$annotations[] = '@' . $this->_annotationsPrefix . $constraintName . '(name="' . $name . '", columns={' . implode(', ', $columns) . '})';
|
||||
}
|
||||
return implode(', ', $annotations);
|
||||
}
|
||||
|
||||
private function _generateInheritanceAnnotation($metadata)
|
||||
{
|
||||
if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
|
||||
|
@ -656,6 +709,9 @@ public function <methodName>()
|
|||
|
||||
private function _isAssociationIsNullable($associationMapping)
|
||||
{
|
||||
if (isset($associationMapping['id']) && $associationMapping['id']) {
|
||||
return false;
|
||||
}
|
||||
if (isset($associationMapping['joinColumns'])) {
|
||||
$joinColumns = $associationMapping['joinColumns'];
|
||||
} else {
|
||||
|
@ -699,7 +755,7 @@ public function <methodName>()
|
|||
}
|
||||
|
||||
$lines[] = $this->_generateAssociationMappingPropertyDocBlock($associationMapping, $metadata);
|
||||
$lines[] = $this->_spaces . 'private $' . $associationMapping['fieldName']
|
||||
$lines[] = $this->_spaces . $this->_fieldVisibility . ' $' . $associationMapping['fieldName']
|
||||
. ($associationMapping['type'] == 'manyToMany' ? ' = array()' : null) . ";\n";
|
||||
}
|
||||
|
||||
|
@ -717,7 +773,7 @@ public function <methodName>()
|
|||
}
|
||||
|
||||
$lines[] = $this->_generateFieldMappingPropertyDocBlock($fieldMapping, $metadata);
|
||||
$lines[] = $this->_spaces . 'private $' . $fieldMapping['fieldName']
|
||||
$lines[] = $this->_spaces . $this->_fieldVisibility . ' $' . $fieldMapping['fieldName']
|
||||
. (isset($fieldMapping['default']) ? ' = ' . var_export($fieldMapping['default'], true) : null) . ";\n";
|
||||
}
|
||||
|
||||
|
@ -1088,4 +1144,4 @@ public function <methodName>()
|
|||
throw new \InvalidArgumentException('Invalid provided IdGeneratorType: ' . $type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,10 @@ class XmlExporter extends AbstractExporter
|
|||
}
|
||||
}
|
||||
|
||||
$root->addChild('change-tracking-policy', $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy));
|
||||
$trackingPolicy = $this->_getChangeTrackingPolicyString($metadata->changeTrackingPolicy);
|
||||
if ( $trackingPolicy != 'DEFERRED_IMPLICIT') {
|
||||
$root->addChild('change-tracking-policy', $trackingPolicy);
|
||||
}
|
||||
|
||||
if (isset($metadata->table['indexes'])) {
|
||||
$indexesXml = $root->addChild('indexes');
|
||||
|
@ -183,7 +186,17 @@ class XmlExporter extends AbstractExporter
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
$orderMap = array(
|
||||
ClassMetadataInfo::ONE_TO_ONE,
|
||||
ClassMetadataInfo::ONE_TO_MANY,
|
||||
ClassMetadataInfo::MANY_TO_ONE,
|
||||
ClassMetadataInfo::MANY_TO_MANY,
|
||||
);
|
||||
uasort($metadata->associationMappings, function($m1, $m2)use(&$orderMap){
|
||||
$a1 = array_search($m1['type'],$orderMap);
|
||||
$a2 = array_search($m2['type'],$orderMap);
|
||||
return strcmp($a1, $a2);
|
||||
});
|
||||
foreach ($metadata->associationMappings as $name => $associationMapping) {
|
||||
if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_ONE) {
|
||||
$associationMappingXml = $root->addChild('one-to-one');
|
||||
|
@ -204,8 +217,11 @@ class XmlExporter extends AbstractExporter
|
|||
if (isset($associationMapping['inversedBy'])) {
|
||||
$associationMappingXml->addAttribute('inversed-by', $associationMapping['inversedBy']);
|
||||
}
|
||||
if (isset($associationMapping['orphanRemoval'])) {
|
||||
$associationMappingXml->addAttribute('orphan-removal', $associationMapping['orphanRemoval']);
|
||||
if (isset($associationMapping['indexBy'])) {
|
||||
$associationMappingXml->addAttribute('index-by', $associationMapping['indexBy']);
|
||||
}
|
||||
if (isset($associationMapping['orphanRemoval']) && $associationMapping['orphanRemoval']!==false) {
|
||||
$associationMappingXml->addAttribute('orphan-removal', 'true');
|
||||
}
|
||||
if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) {
|
||||
$joinTableXml = $associationMappingXml->addChild('join-table');
|
||||
|
@ -290,7 +306,7 @@ class XmlExporter extends AbstractExporter
|
|||
}
|
||||
}
|
||||
|
||||
if (isset($metadata->lifecycleCallbacks)) {
|
||||
if (isset($metadata->lifecycleCallbacks) && count($metadata->lifecycleCallbacks)>0) {
|
||||
$lifecycleCallbacksXml = $root->addChild('lifecycle-callbacks');
|
||||
foreach ($metadata->lifecycleCallbacks as $name => $methods) {
|
||||
foreach ($methods as $method) {
|
||||
|
@ -317,4 +333,4 @@ class XmlExporter extends AbstractExporter
|
|||
$result = $dom->saveXML();
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
80
lib/Doctrine/ORM/Tools/Pagination/CountWalker.php
Normal file
80
lib/Doctrine/ORM/Tools/Pagination/CountWalker.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
/**
|
||||
* Doctrine ORM
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* This source file is subject to the new BSD license that is bundled
|
||||
* with this package in the file LICENSE.txt.
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to kontakt@beberlei.de so I can send you a copy immediately.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\ORM\Query\TreeWalkerAdapter,
|
||||
Doctrine\ORM\Query\AST\SelectStatement,
|
||||
Doctrine\ORM\Query\AST\SelectExpression,
|
||||
Doctrine\ORM\Query\AST\PathExpression,
|
||||
Doctrine\ORM\Query\AST\AggregateExpression;
|
||||
|
||||
/**
|
||||
* Replaces the selectClause of the AST with a COUNT statement
|
||||
*
|
||||
* @category DoctrineExtensions
|
||||
* @package DoctrineExtensions\Paginate
|
||||
* @author David Abdemoulaie <dave@hobodave.com>
|
||||
* @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
|
||||
* @license http://hobodave.com/license.txt New BSD License
|
||||
*/
|
||||
class CountWalker extends TreeWalkerAdapter
|
||||
{
|
||||
/**
|
||||
* Distinct mode hint name
|
||||
*/
|
||||
const HINT_DISTINCT = 'doctrine_paginator.distinct';
|
||||
|
||||
/**
|
||||
* Walks down a SelectStatement AST node, modifying it to retrieve a COUNT
|
||||
*
|
||||
* @param SelectStatement $AST
|
||||
* @return void
|
||||
*/
|
||||
public function walkSelectStatement(SelectStatement $AST)
|
||||
{
|
||||
$rootComponents = array();
|
||||
foreach ($this->_getQueryComponents() AS $dqlAlias => $qComp) {
|
||||
$isParent = array_key_exists('parent', $qComp)
|
||||
&& $qComp['parent'] === null
|
||||
&& $qComp['nestingLevel'] == 0
|
||||
;
|
||||
if ($isParent) {
|
||||
$rootComponents[] = array($dqlAlias => $qComp);
|
||||
}
|
||||
}
|
||||
if (count($rootComponents) > 1) {
|
||||
throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction");
|
||||
}
|
||||
$root = reset($rootComponents);
|
||||
$parentName = key($root);
|
||||
$parent = current($root);
|
||||
|
||||
$pathExpression = new PathExpression(
|
||||
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $parentName,
|
||||
$parent['metadata']->getSingleIdentifierFieldName()
|
||||
);
|
||||
$pathExpression->type = PathExpression::TYPE_STATE_FIELD;
|
||||
|
||||
$distinct = $this->_getQuery()->getHint(self::HINT_DISTINCT);
|
||||
$AST->selectClause->selectExpressions = array(
|
||||
new SelectExpression(
|
||||
new AggregateExpression('count', $pathExpression, $distinct), null
|
||||
)
|
||||
);
|
||||
|
||||
// ORDER BY is not needed, only increases query execution through unnecessary sorting.
|
||||
$AST->orderByClause = null;
|
||||
}
|
||||
}
|
||||
|
115
lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php
Normal file
115
lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Doctrine ORM
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* This source file is subject to the new BSD license that is bundled
|
||||
* with this package in the file LICENSE. This license can also be viewed
|
||||
* at http://hobodave.com/license.txt
|
||||
*
|
||||
* @category DoctrineExtensions
|
||||
* @package DoctrineExtensions\Paginate
|
||||
* @author David Abdemoulaie <dave@hobodave.com>
|
||||
* @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
|
||||
* @license http://hobodave.com/license.txt New BSD License
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\DBAL\Types\Type,
|
||||
Doctrine\ORM\Query\TreeWalkerAdapter,
|
||||
Doctrine\ORM\Query\AST\SelectStatement,
|
||||
Doctrine\ORM\Query\AST\SelectExpression,
|
||||
Doctrine\ORM\Query\AST\PathExpression,
|
||||
Doctrine\ORM\Query\AST\AggregateExpression;
|
||||
|
||||
/**
|
||||
* Replaces the selectClause of the AST with a SELECT DISTINCT root.id equivalent
|
||||
*
|
||||
* @category DoctrineExtensions
|
||||
* @package DoctrineExtensions\Paginate
|
||||
* @author David Abdemoulaie <dave@hobodave.com>
|
||||
* @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
|
||||
* @license http://hobodave.com/license.txt New BSD License
|
||||
*/
|
||||
class LimitSubqueryWalker extends TreeWalkerAdapter
|
||||
{
|
||||
/**
|
||||
* ID type hint
|
||||
*/
|
||||
const IDENTIFIER_TYPE = 'doctrine_paginator.id.type';
|
||||
|
||||
/**
|
||||
* @var int Counter for generating unique order column aliases
|
||||
*/
|
||||
private $_aliasCounter = 0;
|
||||
|
||||
/**
|
||||
* Walks down a SelectStatement AST node, modifying it to retrieve DISTINCT ids
|
||||
* of the root Entity
|
||||
*
|
||||
* @param SelectStatement $AST
|
||||
* @return void
|
||||
*/
|
||||
public function walkSelectStatement(SelectStatement $AST)
|
||||
{
|
||||
$parent = null;
|
||||
$parentName = null;
|
||||
$selectExpressions = array();
|
||||
|
||||
foreach ($this->_getQueryComponents() AS $dqlAlias => $qComp) {
|
||||
// preserve mixed data in query for ordering
|
||||
if (isset($qComp['resultVariable'])) {
|
||||
$selectExpressions[] = new SelectExpression($qComp['resultVariable'], $dqlAlias);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($qComp['parent'] === null && $qComp['nestingLevel'] == 0) {
|
||||
$parent = $qComp;
|
||||
$parentName = $dqlAlias;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$identifier = $parent['metadata']->getSingleIdentifierFieldName();
|
||||
$this->_getQuery()->setHint(
|
||||
self::IDENTIFIER_TYPE,
|
||||
Type::getType($parent['metadata']->getTypeOfField($identifier))
|
||||
);
|
||||
|
||||
$pathExpression = new PathExpression(
|
||||
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION,
|
||||
$parentName,
|
||||
$identifier
|
||||
);
|
||||
$pathExpression->type = PathExpression::TYPE_STATE_FIELD;
|
||||
|
||||
array_unshift($selectExpressions, new SelectExpression($pathExpression, '_dctrn_id'));
|
||||
$AST->selectClause->selectExpressions = $selectExpressions;
|
||||
|
||||
if (isset($AST->orderByClause)) {
|
||||
foreach ($AST->orderByClause->orderByItems as $item) {
|
||||
if ($item->expression instanceof PathExpression) {
|
||||
$pathExpression = new PathExpression(
|
||||
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION,
|
||||
$item->expression->identificationVariable,
|
||||
$item->expression->field
|
||||
);
|
||||
$pathExpression->type = PathExpression::TYPE_STATE_FIELD;
|
||||
$AST->selectClause->selectExpressions[] = new SelectExpression(
|
||||
$pathExpression,
|
||||
'_dctrn_ord' . $this->_aliasCounter++
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$AST->selectClause->isDistinct = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
180
lib/Doctrine/ORM/Tools/Pagination/Paginator.php
Normal file
180
lib/Doctrine/ORM/Tools/Pagination/Paginator.php
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?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\Tools\Pagination;
|
||||
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\Tools\Pagination\WhereInWalker;
|
||||
use Doctrine\ORM\Tools\Pagination\CountWalker;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use ArrayIterator;
|
||||
|
||||
/**
|
||||
* Paginator
|
||||
*
|
||||
* The paginator can handle various complex scenarios with DQL.
|
||||
*
|
||||
* @author Pablo Díez <pablodip@gmail.com>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @license New BSD
|
||||
*/
|
||||
class Paginator implements \Countable, \IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @var Query
|
||||
*/
|
||||
private $query;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $fetchJoinCollection;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $count;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Query|QueryBuilder $query A Doctrine ORM query or query builder.
|
||||
* @param Boolean $fetchJoinCollection Whether the query joins a collection (true by default).
|
||||
*/
|
||||
public function __construct($query, $fetchJoinCollection = true)
|
||||
{
|
||||
if ($query instanceof QueryBuilder) {
|
||||
$query = $query->getQuery();
|
||||
}
|
||||
|
||||
$this->query = $query;
|
||||
$this->fetchJoinCollection = (Boolean) $fetchJoinCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the query
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the query joins a collection.
|
||||
*
|
||||
* @return Boolean Whether the query joins a collection.
|
||||
*/
|
||||
public function getFetchJoinCollection()
|
||||
{
|
||||
return $this->fetchJoinCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
if ($this->count === null) {
|
||||
/* @var $countQuery Query */
|
||||
$countQuery = $this->cloneQuery($this->query);
|
||||
|
||||
if ( ! $countQuery->getHint(CountWalker::HINT_DISTINCT)) {
|
||||
$countQuery->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
}
|
||||
|
||||
$countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker'));
|
||||
$countQuery->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
try {
|
||||
$data = $countQuery->getScalarResult();
|
||||
$data = array_map('current', $data);
|
||||
$this->count = array_sum($data);
|
||||
} catch(NoResultException $e) {
|
||||
$this->count = 0;
|
||||
}
|
||||
}
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
$offset = $this->query->getFirstResult();
|
||||
$length = $this->query->getMaxResults();
|
||||
|
||||
if ($this->fetchJoinCollection) {
|
||||
$subQuery = $this->cloneQuery($this->query);
|
||||
$subQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker'))
|
||||
->setFirstResult($offset)
|
||||
->setMaxResults($length);
|
||||
|
||||
$ids = array_map('current', $subQuery->getScalarResult());
|
||||
|
||||
$whereInQuery = $this->cloneQuery($this->query);
|
||||
// don't do this for an empty id array
|
||||
if (count($ids) > 0) {
|
||||
$namespace = WhereInWalker::PAGINATOR_ID_ALIAS;
|
||||
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, count($ids));
|
||||
$whereInQuery->setFirstResult(null)->setMaxResults(null);
|
||||
foreach ($ids as $i => $id) {
|
||||
$i++;
|
||||
$whereInQuery->setParameter("{$namespace}_{$i}", $id);
|
||||
}
|
||||
}
|
||||
|
||||
$result = $whereInQuery->getResult($this->query->getHydrationMode());
|
||||
} else {
|
||||
$result = $this->cloneQuery($this->query)
|
||||
->setMaxResults($length)
|
||||
->setFirstResult($offset)
|
||||
->getResult($this->query->getHydrationMode())
|
||||
;
|
||||
}
|
||||
return new \ArrayIterator($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones a query.
|
||||
*
|
||||
* @param Query $query The query.
|
||||
*
|
||||
* @return Query The cloned query.
|
||||
*/
|
||||
private function cloneQuery(Query $query)
|
||||
{
|
||||
/* @var $cloneQuery Query */
|
||||
$cloneQuery = clone $query;
|
||||
$cloneQuery->setParameters($query->getParameters());
|
||||
foreach ($query->getHints() as $name => $value) {
|
||||
$cloneQuery->setHint($name, $value);
|
||||
}
|
||||
|
||||
return $cloneQuery;
|
||||
}
|
||||
}
|
||||
|
144
lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php
Normal file
144
lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
/**
|
||||
* Doctrine ORM
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* This source file is subject to the new BSD license that is bundled
|
||||
* with this package in the file LICENSE. This license can also be viewed
|
||||
* at http://hobodave.com/license.txt
|
||||
*
|
||||
* @category DoctrineExtensions
|
||||
* @package DoctrineExtensions\Paginate
|
||||
* @author David Abdemoulaie <dave@hobodave.com>
|
||||
* @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
|
||||
* @license http://hobodave.com/license.txt New BSD License
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\ORM\Query\AST\ArithmeticExpression,
|
||||
Doctrine\ORM\Query\AST\SimpleArithmeticExpression,
|
||||
Doctrine\ORM\Query\TreeWalkerAdapter,
|
||||
Doctrine\ORM\Query\AST\SelectStatement,
|
||||
Doctrine\ORM\Query\AST\PathExpression,
|
||||
Doctrine\ORM\Query\AST\InExpression,
|
||||
Doctrine\ORM\Query\AST\NullComparisonExpression,
|
||||
Doctrine\ORM\Query\AST\InputParameter,
|
||||
Doctrine\ORM\Query\AST\ConditionalPrimary,
|
||||
Doctrine\ORM\Query\AST\ConditionalTerm,
|
||||
Doctrine\ORM\Query\AST\ConditionalExpression,
|
||||
Doctrine\ORM\Query\AST\ConditionalFactor,
|
||||
Doctrine\ORM\Query\AST\WhereClause;
|
||||
|
||||
/**
|
||||
* Replaces the whereClause of the AST with a WHERE id IN (:foo_1, :foo_2) equivalent
|
||||
*
|
||||
* @category DoctrineExtensions
|
||||
* @package DoctrineExtensions\Paginate
|
||||
* @author David Abdemoulaie <dave@hobodave.com>
|
||||
* @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
|
||||
* @license http://hobodave.com/license.txt New BSD License
|
||||
*/
|
||||
class WhereInWalker extends TreeWalkerAdapter
|
||||
{
|
||||
/**
|
||||
* ID Count hint name
|
||||
*/
|
||||
const HINT_PAGINATOR_ID_COUNT = 'doctrine.id.count';
|
||||
|
||||
/**
|
||||
* Primary key alias for query
|
||||
*/
|
||||
const PAGINATOR_ID_ALIAS = 'dpid';
|
||||
|
||||
/**
|
||||
* Replaces the whereClause in the AST
|
||||
*
|
||||
* Generates a clause equivalent to WHERE IN (:dpid_1, :dpid_2, ...)
|
||||
*
|
||||
* The parameter namespace (dpid) is defined by
|
||||
* the PAGINATOR_ID_ALIAS
|
||||
*
|
||||
* The total number of parameters is retrieved from
|
||||
* the HINT_PAGINATOR_ID_COUNT query hint
|
||||
*
|
||||
* @param SelectStatement $AST
|
||||
* @return void
|
||||
*/
|
||||
public function walkSelectStatement(SelectStatement $AST)
|
||||
{
|
||||
$rootComponents = array();
|
||||
foreach ($this->_getQueryComponents() AS $dqlAlias => $qComp) {
|
||||
$isParent = array_key_exists('parent', $qComp)
|
||||
&& $qComp['parent'] === null
|
||||
&& $qComp['nestingLevel'] == 0
|
||||
;
|
||||
if ($isParent) {
|
||||
$rootComponents[] = array($dqlAlias => $qComp);
|
||||
}
|
||||
}
|
||||
if (count($rootComponents) > 1) {
|
||||
throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction");
|
||||
}
|
||||
$root = reset($rootComponents);
|
||||
$parentName = key($root);
|
||||
$parent = current($root);
|
||||
|
||||
$pathExpression = new PathExpression(
|
||||
PathExpression::TYPE_STATE_FIELD, $parentName, $parent['metadata']->getSingleIdentifierFieldName()
|
||||
);
|
||||
$pathExpression->type = PathExpression::TYPE_STATE_FIELD;
|
||||
|
||||
$count = $this->_getQuery()->getHint(self::HINT_PAGINATOR_ID_COUNT);
|
||||
|
||||
if ($count > 0) {
|
||||
$arithmeticExpression = new ArithmeticExpression();
|
||||
$arithmeticExpression->simpleArithmeticExpression = new SimpleArithmeticExpression(
|
||||
array($pathExpression)
|
||||
);
|
||||
$expression = new InExpression($arithmeticExpression);
|
||||
$ns = self::PAGINATOR_ID_ALIAS;
|
||||
|
||||
for ($i = 1; $i <= $count; $i++) {
|
||||
$expression->literals[] = new InputParameter(":{$ns}_$i");
|
||||
}
|
||||
} else {
|
||||
$expression = new NullComparisonExpression($pathExpression);
|
||||
$expression->not = false;
|
||||
}
|
||||
|
||||
$conditionalPrimary = new ConditionalPrimary;
|
||||
$conditionalPrimary->simpleConditionalExpression = $expression;
|
||||
if ($AST->whereClause) {
|
||||
if ($AST->whereClause->conditionalExpression instanceof ConditionalTerm) {
|
||||
$AST->whereClause->conditionalExpression->conditionalFactors[] = $conditionalPrimary;
|
||||
} elseif ($AST->whereClause->conditionalExpression instanceof ConditionalPrimary) {
|
||||
$AST->whereClause->conditionalExpression = new ConditionalExpression(array(
|
||||
new ConditionalTerm(array(
|
||||
$AST->whereClause->conditionalExpression,
|
||||
$conditionalPrimary
|
||||
))
|
||||
));
|
||||
} elseif ($AST->whereClause->conditionalExpression instanceof ConditionalExpression
|
||||
|| $AST->whereClause->conditionalExpression instanceof ConditionalFactor
|
||||
) {
|
||||
$tmpPrimary = new ConditionalPrimary;
|
||||
$tmpPrimary->conditionalExpression = $AST->whereClause->conditionalExpression;
|
||||
$AST->whereClause->conditionalExpression = new ConditionalTerm(array(
|
||||
$tmpPrimary,
|
||||
$conditionalPrimary
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$AST->whereClause = new WhereClause(
|
||||
new ConditionalExpression(array(
|
||||
new ConditionalTerm(array(
|
||||
$conditionalPrimary
|
||||
))
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,8 @@ namespace Doctrine\ORM\Tools;
|
|||
|
||||
use Doctrine\ORM\ORMException,
|
||||
Doctrine\DBAL\Types\Type,
|
||||
Doctrine\DBAL\Schema\Schema,
|
||||
Doctrine\DBAL\Schema\Visitor\RemoveNamespacedAssets,
|
||||
Doctrine\ORM\EntityManager,
|
||||
Doctrine\ORM\Mapping\ClassMetadata,
|
||||
Doctrine\ORM\Internal\CommitOrderCalculator,
|
||||
|
@ -127,7 +129,7 @@ class SchemaTool
|
|||
$sm = $this->_em->getConnection()->getSchemaManager();
|
||||
$metadataSchemaConfig = $sm->createSchemaConfig();
|
||||
$metadataSchemaConfig->setExplicitForeignKeyIndexes(false);
|
||||
$schema = new \Doctrine\DBAL\Schema\Schema(array(), array(), $metadataSchemaConfig);
|
||||
$schema = new Schema(array(), array(), $metadataSchemaConfig);
|
||||
|
||||
$evm = $this->_em->getEventManager();
|
||||
|
||||
|
@ -223,13 +225,19 @@ class SchemaTool
|
|||
|
||||
if (isset($class->table['indexes'])) {
|
||||
foreach ($class->table['indexes'] AS $indexName => $indexData) {
|
||||
$table->addIndex($indexData['columns'], $indexName);
|
||||
$table->addIndex($indexData['columns'], is_numeric($indexName) ? null : $indexName);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($class->table['uniqueConstraints'])) {
|
||||
foreach ($class->table['uniqueConstraints'] AS $indexName => $indexData) {
|
||||
$table->addUniqueIndex($indexData['columns'], $indexName);
|
||||
$table->addUniqueIndex($indexData['columns'], is_numeric($indexName) ? null : $indexName);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($class->table['options'])) {
|
||||
foreach ($class->table['options'] AS $key => $val) {
|
||||
$table->addOption($key, $val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,6 +260,10 @@ class SchemaTool
|
|||
}
|
||||
}
|
||||
|
||||
if ( ! $this->_platform->supportsSchemas() && ! $this->_platform->canEmulateSchemas() ) {
|
||||
$schema->visit(new RemoveNamespacedAssets());
|
||||
}
|
||||
|
||||
if ($evm->hasListeners(ToolEvents::postGenerateSchema)) {
|
||||
$evm->dispatchEvent(ToolEvents::postGenerateSchema, new GenerateSchemaEventArgs($this->_em, $schema));
|
||||
}
|
||||
|
@ -276,11 +288,16 @@ class SchemaTool
|
|||
$discrColumn['length'] = 255;
|
||||
}
|
||||
|
||||
$table->addColumn(
|
||||
$discrColumn['name'],
|
||||
$discrColumn['type'],
|
||||
array('length' => $discrColumn['length'], 'notnull' => true)
|
||||
$options = array(
|
||||
'length' => isset($discrColumn['length']) ? $discrColumn['length'] : null,
|
||||
'notnull' => true
|
||||
);
|
||||
|
||||
if (isset($discrColumn['columnDefinition'])) {
|
||||
$options['columnDefinition'] = $discrColumn['columnDefinition'];
|
||||
}
|
||||
|
||||
$table->addColumn($discrColumn['name'], $discrColumn['type'], $options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -360,6 +377,10 @@ class SchemaTool
|
|||
$options['columnDefinition'] = $mapping['columnDefinition'];
|
||||
}
|
||||
|
||||
if (isset($mapping['options'])) {
|
||||
$options['customSchemaOptions'] = $mapping['options'];
|
||||
}
|
||||
|
||||
if ($class->isIdGeneratorIdentity() && $class->getIdentifierFieldNames() == array($mapping['fieldName'])) {
|
||||
$options['autoincrement'] = true;
|
||||
}
|
||||
|
|
|
@ -95,8 +95,8 @@ class SchemaValidator
|
|||
}
|
||||
|
||||
foreach ($class->associationMappings AS $fieldName => $assoc) {
|
||||
if (!$cmf->hasMetadataFor($assoc['targetEntity'])) {
|
||||
$ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown.';
|
||||
if (!class_exists($assoc['targetEntity']) || $cmf->isTransient($assoc['targetEntity'])) {
|
||||
$ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown or not an entity.';
|
||||
return $ce;
|
||||
}
|
||||
|
||||
|
@ -106,6 +106,11 @@ class SchemaValidator
|
|||
|
||||
$targetMetadata = $cmf->getMetadataFor($assoc['targetEntity']);
|
||||
|
||||
if (isset($assoc['id']) && $targetMetadata->containsForeignIdentifier) {
|
||||
$ce[] = "Cannot map association '" . $class->name. "#". $fieldName ." as identifier, because " .
|
||||
"the target entity '". $targetMetadata->name . "' also maps an association as identifier.";
|
||||
}
|
||||
|
||||
/* @var $assoc AssociationMapping */
|
||||
if ($assoc['mappedBy']) {
|
||||
if ($targetMetadata->hasField($assoc['mappedBy'])) {
|
||||
|
@ -119,7 +124,7 @@ class SchemaValidator
|
|||
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the inverse side of a ".
|
||||
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
|
||||
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
|
||||
"'inversedBy' attribute.";
|
||||
"'inversedBy=".$fieldName."' attribute.";
|
||||
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] != $fieldName) {
|
||||
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
|
||||
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " are ".
|
||||
|
@ -162,30 +167,21 @@ class SchemaValidator
|
|||
|
||||
if ($assoc['isOwningSide']) {
|
||||
if ($assoc['type'] == ClassMetadataInfo::MANY_TO_MANY) {
|
||||
$identifierColumns = $class->getIdentifierColumnNames();
|
||||
foreach ($assoc['joinTable']['joinColumns'] AS $joinColumn) {
|
||||
if (!isset($class->fieldNames[$joinColumn['referencedColumnName']])) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
|
||||
"have a corresponding field with this column name on the class '" . $class->name . "'.";
|
||||
break;
|
||||
}
|
||||
|
||||
$fieldName = $class->fieldNames[$joinColumn['referencedColumnName']];
|
||||
if (!in_array($fieldName, $class->identifier)) {
|
||||
if (!in_array($joinColumn['referencedColumnName'], $identifierColumns)) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
|
||||
"has to be a primary key column.";
|
||||
"has to be a primary key column on the target entity class '".$class->name."'.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach ($assoc['joinTable']['inverseJoinColumns'] AS $inverseJoinColumn) {
|
||||
if (!isset($targetMetadata->fieldNames[$inverseJoinColumn['referencedColumnName']])) {
|
||||
$ce[] = "The inverse referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' does not " .
|
||||
"have a corresponding field with this column name on the class '" . $targetMetadata->name . "'.";
|
||||
break;
|
||||
}
|
||||
|
||||
$fieldName = $targetMetadata->fieldNames[$inverseJoinColumn['referencedColumnName']];
|
||||
if (!in_array($fieldName, $targetMetadata->identifier)) {
|
||||
$ce[] = "The referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' " .
|
||||
"has to be a primary key column.";
|
||||
$identifierColumns = $targetMetadata->getIdentifierColumnNames();
|
||||
foreach ($assoc['joinTable']['inverseJoinColumns'] AS $inverseJoinColumn) {
|
||||
if (!in_array($inverseJoinColumn['referencedColumnName'], $identifierColumns)) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
|
||||
"has to be a primary key column on the target entity class '".$targetMetadata->name."'.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,29 +200,23 @@ class SchemaValidator
|
|||
}
|
||||
|
||||
} else if ($assoc['type'] & ClassMetadataInfo::TO_ONE) {
|
||||
$identifierColumns = $targetMetadata->getIdentifierColumnNames();
|
||||
foreach ($assoc['joinColumns'] AS $joinColumn) {
|
||||
if (!isset($targetMetadata->fieldNames[$joinColumn['referencedColumnName']])) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
|
||||
"have a corresponding field with this column name on the class '" . $targetMetadata->name . "'.";
|
||||
break;
|
||||
}
|
||||
|
||||
$fieldName = $targetMetadata->fieldNames[$joinColumn['referencedColumnName']];
|
||||
if (!in_array($fieldName, $targetMetadata->identifier)) {
|
||||
if (!in_array($joinColumn['referencedColumnName'], $identifierColumns)) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
|
||||
"has to be a primary key column.";
|
||||
"has to be a primary key column on the target entity class '".$targetMetadata->name."'.";
|
||||
}
|
||||
}
|
||||
|
||||
if (count($class->getIdentifierColumnNames()) != count($assoc['joinColumns'])) {
|
||||
if (count($identifierColumns) != count($assoc['joinColumns'])) {
|
||||
$ids = array();
|
||||
foreach ($assoc['joinColumns'] AS $joinColumn) {
|
||||
$ids[] = $joinColumn['name'];
|
||||
}
|
||||
|
||||
$ce[] = "The join columns of the association '" . $assoc['fieldName'] . "' " .
|
||||
"have to match to ALL identifier columns of the source entity '". $class->name . "', " .
|
||||
"however '" . implode(", ", array_diff($class->getIdentifierColumnNames(), $ids)) .
|
||||
"have to match to ALL identifier columns of the target entity '". $class->name . "', " .
|
||||
"however '" . implode(", ", array_diff($targetMetadata->getIdentifierColumnNames(), $ids)) .
|
||||
"' are missing.";
|
||||
}
|
||||
}
|
||||
|
@ -260,6 +250,28 @@ class SchemaValidator
|
|||
return $ce;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $columnName
|
||||
* @param ClassMetadataInfo $class
|
||||
* @return bool
|
||||
*/
|
||||
private function columnExistsOnEntity($columnName, $class)
|
||||
{
|
||||
if (isset($class->fieldNames[$columnName])) {
|
||||
return true;
|
||||
}
|
||||
foreach ($class->associationMappings as $assoc) {
|
||||
if ($assoc['isOwningSide']) {
|
||||
foreach ($assoc['joinColumns'] as $columnMapping) {
|
||||
if ($columnMapping['name'] == $columnName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Database Schema is in sync with the current metadata state.
|
||||
*
|
||||
|
|
|
@ -390,7 +390,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
*/
|
||||
private function computeSingleEntityChangeSet($entity)
|
||||
{
|
||||
if ( ! $this->isInIdentityMap($entity) ) {
|
||||
if ( $this->getEntityState($entity) !== self::STATE_MANAGED) {
|
||||
throw new \InvalidArgumentException("Entity has to be managed for single computation " . self::objToStr($entity));
|
||||
}
|
||||
|
||||
|
@ -584,6 +584,23 @@ class UnitOfWork implements PropertyChangedListener
|
|||
|
||||
$assoc = $class->associationMappings[$propName];
|
||||
|
||||
// Persistent collection was exchanged with the "originally"
|
||||
// created one. This can only mean it was cloned and replaced
|
||||
// on another entity.
|
||||
if ($actualValue instanceof PersistentCollection) {
|
||||
$owner = $actualValue->getOwner();
|
||||
if ($owner === null) { // cloned
|
||||
$actualValue->setOwner($entity, $assoc);
|
||||
} else if ($owner !== $entity) { // no clone, we have to fix
|
||||
if (!$actualValue->isInitialized()) {
|
||||
$actualValue->initialize(); // we have to do this otherwise the cols share state
|
||||
}
|
||||
$newValue = clone $actualValue;
|
||||
$newValue->setOwner($entity, $assoc);
|
||||
$class->reflFields[$propName]->setValue($entity, $newValue);
|
||||
}
|
||||
}
|
||||
|
||||
if ($orgValue instanceof PersistentCollection) {
|
||||
// A PersistentCollection was de-referenced, so delete it.
|
||||
$coid = spl_object_hash($orgValue);
|
||||
|
@ -705,7 +722,18 @@ class UnitOfWork implements PropertyChangedListener
|
|||
|
||||
foreach ($unwrappedValue as $key => $entry) {
|
||||
$state = $this->getEntityState($entry, self::STATE_NEW);
|
||||
$oid = spl_object_hash($entry);
|
||||
|
||||
if ( ! ($entry instanceof $assoc['targetEntity'])) {
|
||||
throw new ORMException(
|
||||
sprintf(
|
||||
'Found entity of type %s on association %s#%s, but expecting %s',
|
||||
get_class($entry),
|
||||
$assoc['sourceEntity'],
|
||||
$assoc['fieldName'],
|
||||
$targetClass->name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
switch ($state) {
|
||||
case self::STATE_NEW:
|
||||
|
@ -1001,7 +1029,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
// are not yet available.
|
||||
$newNodes = array();
|
||||
|
||||
foreach ($entityChangeSet as $oid => $entity) {
|
||||
foreach ($entityChangeSet as $entity) {
|
||||
$className = get_class($entity);
|
||||
|
||||
if ($calc->hasClass($className)) {
|
||||
|
@ -1367,6 +1395,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
|
||||
if (isset($this->identityMap[$className][$idHash])) {
|
||||
unset($this->identityMap[$className][$idHash]);
|
||||
unset($this->readOnlyObjects[$oid]);
|
||||
|
||||
//$this->entityStates[$oid] = self::STATE_DETACHED;
|
||||
|
||||
|
@ -1647,7 +1676,8 @@ class UnitOfWork implements PropertyChangedListener
|
|||
foreach ($id as $idField => $idValue) {
|
||||
if (isset($class->associationMappings[$idField])) {
|
||||
$targetClassMetadata = $this->em->getClassMetadata($class->associationMappings[$idField]['targetEntity']);
|
||||
$associatedId = $this->getEntityIdentifier($idValue);
|
||||
$associatedId = $this->getEntityIdentifier($idValue);
|
||||
|
||||
$flatId[$idField] = $associatedId[$targetClassMetadata->identifier[0]];
|
||||
}
|
||||
}
|
||||
|
@ -1676,6 +1706,10 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$class->setIdentifierValues($managedCopy, $id);
|
||||
|
||||
$this->persistNew($class, $managedCopy);
|
||||
} else {
|
||||
if ($managedCopy instanceof Proxy && ! $managedCopy->__isInitialized__) {
|
||||
$managedCopy->__load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2176,6 +2210,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$this->collectionDeletions =
|
||||
$this->collectionUpdates =
|
||||
$this->extraUpdates =
|
||||
$this->readOnlyObjects =
|
||||
$this->orphanRemovals = array();
|
||||
|
||||
if ($this->commitOrderCalculator !== null) {
|
||||
|
@ -2405,9 +2440,9 @@ class UnitOfWork implements PropertyChangedListener
|
|||
case (isset($this->identityMap[$targetClass->rootEntityName][$relatedIdHash])):
|
||||
$newValue = $this->identityMap[$targetClass->rootEntityName][$relatedIdHash];
|
||||
|
||||
// if this is an uninitialized proxy, we are deferring eager loads,
|
||||
// If this is an uninitialized proxy, we are deferring eager loads,
|
||||
// this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
|
||||
// then we cann append this entity for eager loading!
|
||||
// then we can append this entity for eager loading!
|
||||
if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER &&
|
||||
isset($hints['deferEagerLoad']) &&
|
||||
!$targetClass->isIdentifierComposite &&
|
||||
|
@ -2485,6 +2520,17 @@ class UnitOfWork implements PropertyChangedListener
|
|||
}
|
||||
}
|
||||
|
||||
if ($overrideLocalValues) {
|
||||
if (isset($class->lifecycleCallbacks[Events::postLoad])) {
|
||||
$class->invokeLifecycleCallbacks(Events::postLoad, $entity);
|
||||
}
|
||||
|
||||
|
||||
if ($this->evm->hasListeners(Events::postLoad)) {
|
||||
$this->evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->em));
|
||||
}
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
|
@ -2502,13 +2548,15 @@ class UnitOfWork implements PropertyChangedListener
|
|||
$this->eagerLoadingEntities = array();
|
||||
|
||||
foreach ($eagerLoadingEntities as $entityName => $ids) {
|
||||
if ( ! $ids) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = $this->em->getClassMetadata($entityName);
|
||||
|
||||
if ($ids) {
|
||||
$this->getEntityPersister($entityName)->loadAll(
|
||||
array_combine($class->identifier, array(array_values($ids)))
|
||||
);
|
||||
}
|
||||
$this->getEntityPersister($entityName)->loadAll(
|
||||
array_combine($class->identifier, array(array_values($ids)))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2888,7 +2936,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||
*/
|
||||
public function isReadOnly($object)
|
||||
{
|
||||
if ( ! is_object($object) ) {
|
||||
if ( ! is_object($object)) {
|
||||
throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
|
||||
}
|
||||
|
||||
|
|
2
lib/vendor/doctrine-dbal
vendored
2
lib/vendor/doctrine-dbal
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 29b714b7fe72641d749ae90324a5759853fe09b0
|
||||
Subproject commit 480b127fb5c35d6fbd70964a228cd63cfe2b7e14
|
|
@ -28,7 +28,7 @@ class CompanyPerson
|
|||
*/
|
||||
private $name;
|
||||
/**
|
||||
* @OneToOne(targetEntity="CompanyPerson", mappedBy="spouse")
|
||||
* @OneToOne(targetEntity="CompanyPerson")
|
||||
* @JoinColumn(name="spouse_id", referencedColumnName="id")
|
||||
*/
|
||||
private $spouse;
|
||||
|
|
|
@ -18,4 +18,9 @@ class CustomTypeUpperCase
|
|||
* @Column(type="upper_case_string")
|
||||
*/
|
||||
public $lowerCaseString;
|
||||
|
||||
/**
|
||||
* @Column(type="upper_case_string", name="named_lower_case_string", nullable = true)
|
||||
*/
|
||||
public $namedLowerCaseString;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ class DDC117Reference
|
|||
|
||||
/**
|
||||
* @Id
|
||||
* @ManyToOne(targetEntity="DDC117Article", inversedBy="references")
|
||||
* @ManyToOne(targetEntity="DDC117Article")
|
||||
* @JoinColumn(name="target_id", referencedColumnName="article_id")
|
||||
*/
|
||||
private $target;
|
||||
|
@ -61,4 +61,4 @@ class DDC117Reference
|
|||
{
|
||||
return $this->description;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ class DDC117Translation
|
|||
{
|
||||
/**
|
||||
* @Id
|
||||
* @ManyToOne(targetEntity="DDC117Article")
|
||||
* @ManyToOne(targetEntity="DDC117Article", inversedBy="translations")
|
||||
* @JoinColumn(name="article_id", referencedColumnName="article_id")
|
||||
*/
|
||||
private $article;
|
||||
|
@ -62,4 +62,4 @@ class DDC117Translation
|
|||
{
|
||||
return $this->reviewedByEditors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class LegacyUserReference
|
|||
|
||||
/**
|
||||
* @Id
|
||||
* @ManyToOne(targetEntity="LegacyUser", inversedBy="_references")
|
||||
* @ManyToOne(targetEntity="LegacyUser")
|
||||
* @JoinColumn(name="iUserIdTarget", referencedColumnName="iUserId")
|
||||
*/
|
||||
private $_target;
|
||||
|
|
|
@ -26,7 +26,7 @@ class NavPointOfInterest
|
|||
private $name;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="NavCountry")
|
||||
* @ManyToOne(targetEntity="NavCountry", inversedBy="pois")
|
||||
*/
|
||||
private $country;
|
||||
|
||||
|
@ -53,4 +53,4 @@ class NavPointOfInterest
|
|||
public function getCountry() {
|
||||
return $this->country;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1141,6 +1141,21 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->_em->flush($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-720
|
||||
* @group DDC-1612
|
||||
*/
|
||||
public function testFlushSingleNewEntity()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Dominik';
|
||||
$user->username = 'domnikl';
|
||||
$user->status = 'developer';
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-720
|
||||
*/
|
||||
|
@ -1197,4 +1212,21 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$user2 = $this->_em->find(get_class($user2), $user2->id);
|
||||
$this->assertEquals('developer', $user2->status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1585
|
||||
*/
|
||||
public function testWrongAssocationInstance()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Dominik';
|
||||
$user->username = 'domnikl';
|
||||
$user->status = 'developer';
|
||||
$user->address = $user;
|
||||
|
||||
$this->_em->persist($user);
|
||||
|
||||
$this->setExpectedException("Doctrine\ORM\ORMException", "Found entity of type Doctrine\Tests\Models\CMS\CmsUser on association Doctrine\Tests\Models\CMS\CmsUser#address, but expecting Doctrine\Tests\Models\CMS\CmsAddress");
|
||||
$this->_em->flush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Functional;
|
|||
use Doctrine\Tests\Models\Navigation\NavCountry;
|
||||
use Doctrine\Tests\Models\Navigation\NavPointOfInterest;
|
||||
use Doctrine\Tests\Models\Navigation\NavTour;
|
||||
use Doctrine\Tests\Models\Navigation\NavPhotos;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
|
@ -51,6 +52,25 @@ class CompositePrimaryKeyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertEquals('Brandenburger Tor', $poi->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1651
|
||||
*/
|
||||
public function testSetParameterCompositeKeyObject()
|
||||
{
|
||||
$this->putGermanysBrandenburderTor();
|
||||
|
||||
$poi = $this->_em->find('Doctrine\Tests\Models\Navigation\NavPointOfInterest', array('lat' => 100, 'long' => 200));
|
||||
$photo = new NavPhotos($poi, "asdf");
|
||||
$this->_em->persist($photo);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$dql = 'SELECT t FROM Doctrine\Tests\Models\Navigation\NavPhotos t WHERE t.poi = ?1';
|
||||
|
||||
$this->setExpectedException('Doctrine\ORM\Query\QueryException', 'A single-valued association path expression to an entity with a composite primary key is not supported.');
|
||||
$sql = $this->_em->createQuery($dql)->getSQL();
|
||||
}
|
||||
|
||||
public function testManyToManyCompositeRelation()
|
||||
{
|
||||
$this->putGermanysBrandenburderTor();
|
||||
|
@ -98,4 +118,4 @@ class CompositePrimaryKeyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->setExpectedException('Doctrine\ORM\ORMException', 'The identifier long is missing for a query of Doctrine\Tests\Models\Navigation\NavPointOfInterest');
|
||||
$poi = $this->_em->find('Doctrine\Tests\Models\Navigation\NavPointOfInterest', array('key1' => 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
/**
|
||||
* @group DDC-546
|
||||
*/
|
||||
public function testCountWhenNewEntitysPresent()
|
||||
public function testCountWhenNewEntityPresent()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
|
||||
|
@ -223,13 +223,15 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
$this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
||||
|
||||
$article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId);
|
||||
|
||||
// Test One to Many existance retrieved from DB
|
||||
$article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId);
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$this->assertTrue($user->articles->contains($article));
|
||||
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
|
||||
// Test One to Many existance with state new
|
||||
$article = new \Doctrine\Tests\Models\CMS\CmsArticle();
|
||||
$article->topic = "Testnew";
|
||||
$article->text = "blub";
|
||||
|
@ -238,12 +240,26 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertFalse($user->articles->contains($article));
|
||||
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of new entity should cause no query to be executed.");
|
||||
|
||||
// Test One to Many existance with state clear
|
||||
$this->_em->persist($article);
|
||||
$this->_em->flush();
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
$this->assertFalse($user->articles->contains($article));
|
||||
$this->assertEquals($queryCount+1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
|
||||
$this->assertEquals($queryCount+1, $this->getCurrentQueryCount(), "Checking for contains of persisted entity should cause one query to be executed.");
|
||||
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
|
||||
// Test One to Many existance with state managed
|
||||
$article = new \Doctrine\Tests\Models\CMS\CmsArticle();
|
||||
$article->topic = "How to not fail anymore on tests";
|
||||
$article->text = "That is simple! Just write more tests!";
|
||||
|
||||
$this->_em->persist($article);
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$this->assertFalse($user->articles->contains($article));
|
||||
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of managed entity (but not persisted) should cause no query to be executed.");
|
||||
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
}
|
||||
|
||||
|
@ -255,6 +271,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
||||
|
||||
// Test Many to Many existance retrieved from DB
|
||||
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
|
@ -262,6 +279,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
|
||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
|
||||
// Test Many to Many existance with state new
|
||||
$group = new \Doctrine\Tests\Models\CMS\CmsGroup();
|
||||
$group->name = "A New group!";
|
||||
|
||||
|
@ -271,13 +289,26 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of new entity should cause no query to be executed.");
|
||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
|
||||
// Test Many to Many existance with state clear
|
||||
$this->_em->persist($group);
|
||||
$this->_em->flush();
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$this->assertFalse($user->groups->contains($group));
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Checking for contains of persisted entity should cause one query to be executed.");
|
||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
|
||||
// Test Many to Many existance with state managed
|
||||
$group = new \Doctrine\Tests\Models\CMS\CmsGroup();
|
||||
$group->name = "My managed group";
|
||||
|
||||
$this->_em->persist($group);
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$this->assertFalse($user->groups->contains($group));
|
||||
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of managed entity (but not persisted) should cause no query to be executed.");
|
||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
}
|
||||
|
||||
|
@ -313,6 +344,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
$this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
||||
|
||||
// Test One to Many removal with Entity retrieved from DB
|
||||
$article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId);
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
|
@ -321,6 +353,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||
|
||||
// Test One to Many removal with Entity state as new
|
||||
$article = new \Doctrine\Tests\Models\CMS\CmsArticle();
|
||||
$article->topic = "Testnew";
|
||||
$article->text = "blub";
|
||||
|
@ -331,6 +364,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
|
||||
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing a new entity should cause no query to be executed.");
|
||||
|
||||
// Test One to Many removal with Entity state as clean
|
||||
$this->_em->persist($article);
|
||||
$this->_em->flush();
|
||||
|
||||
|
@ -338,8 +372,21 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
|
||||
$user->articles->removeElement($article);
|
||||
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a managed entity should cause one query to be executed.");
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a persisted entity should cause one query to be executed.");
|
||||
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
|
||||
// Test One to Many removal with Entity state as managed
|
||||
$article = new \Doctrine\Tests\Models\CMS\CmsArticle();
|
||||
$article->topic = "How to not fail anymore on tests";
|
||||
$article->text = "That is simple! Just write more tests!";
|
||||
|
||||
$this->_em->persist($article);
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$user->articles->removeElement($article);
|
||||
|
||||
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing a managed entity should cause no query to be executed.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -350,14 +397,16 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
||||
|
||||
// Test Many to Many removal with Entity retrieved from DB
|
||||
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$user->groups->removeElement($group);
|
||||
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a managed entity should cause one query to be executed.");
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a persisted entity should cause one query to be executed.");
|
||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
|
||||
// Test Many to Many removal with Entity state as new
|
||||
$group = new \Doctrine\Tests\Models\CMS\CmsGroup();
|
||||
$group->name = "A New group!";
|
||||
|
||||
|
@ -368,6 +417,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing new entity should cause no query to be executed.");
|
||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
|
||||
// Test Many to Many removal with Entity state as clean
|
||||
$this->_em->persist($group);
|
||||
$this->_em->flush();
|
||||
|
||||
|
@ -375,7 +425,20 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
|
||||
$user->groups->removeElement($group);
|
||||
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a managed entity should cause one query to be executed.");
|
||||
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a persisted entity should cause one query to be executed.");
|
||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
|
||||
// Test Many to Many removal with Entity state as managed
|
||||
$group = new \Doctrine\Tests\Models\CMS\CmsGroup();
|
||||
$group->name = "A New group!";
|
||||
|
||||
$this->_em->persist($group);
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
$user->groups->removeElement($group);
|
||||
|
||||
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing a managed entity should cause no query to be executed.");
|
||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
}
|
||||
|
||||
|
|
105
tests/Doctrine/Tests/ORM/Functional/PaginationTest.php
Normal file
105
tests/Doctrine/Tests/ORM/Functional/PaginationTest.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\ORM\Tools\SchemaTool;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
||||
use Doctrine\Tests\Models\CMS\CmsAddress;
|
||||
use Doctrine\Tests\Models\CMS\CmsGroup;
|
||||
use Doctrine\Tests\Models\CMS\CmsArticle;
|
||||
use Doctrine\Tests\Models\CMS\CmsComment;
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
|
||||
/**
|
||||
* @group DDC-1613
|
||||
*/
|
||||
class PaginationTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
$this->populate();
|
||||
}
|
||||
|
||||
public function testCountSimpleWithoutJoin()
|
||||
{
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u";
|
||||
$query = $this->_em->createQuery($dql);
|
||||
|
||||
$paginator = new Paginator($query);
|
||||
$this->assertEquals(3, count($paginator));
|
||||
}
|
||||
|
||||
public function testCountWithFetchJoin()
|
||||
{
|
||||
$dql = "SELECT u,g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g";
|
||||
$query = $this->_em->createQuery($dql);
|
||||
|
||||
$paginator = new Paginator($query);
|
||||
$this->assertEquals(3, count($paginator));
|
||||
}
|
||||
|
||||
public function testIterateSimpleWithoutJoinFetchJoinHandlingOff()
|
||||
{
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u";
|
||||
$query = $this->_em->createQuery($dql);
|
||||
|
||||
$paginator = new Paginator($query, false);
|
||||
|
||||
$data = array();
|
||||
foreach ($paginator as $user) {
|
||||
$data[] = $user;
|
||||
}
|
||||
$this->assertEquals(3, count($data));
|
||||
}
|
||||
|
||||
public function testIterateSimpleWithoutJoinFetchJoinHandlingOn()
|
||||
{
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u";
|
||||
$query = $this->_em->createQuery($dql);
|
||||
|
||||
$paginator = new Paginator($query, true);
|
||||
|
||||
$data = array();
|
||||
foreach ($paginator as $user) {
|
||||
$data[] = $user;
|
||||
}
|
||||
$this->assertEquals(3, count($data));
|
||||
}
|
||||
|
||||
public function testIterateWithFetchJoin()
|
||||
{
|
||||
$dql = "SELECT u,g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g";
|
||||
$query = $this->_em->createQuery($dql);
|
||||
|
||||
$paginator = new Paginator($query, true);
|
||||
|
||||
$data = array();
|
||||
foreach ($paginator as $user) {
|
||||
$data[] = $user;
|
||||
}
|
||||
$this->assertEquals(3, count($data));
|
||||
}
|
||||
|
||||
public function populate()
|
||||
{
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$user = new CmsUser();
|
||||
$user->name = "Name$i";
|
||||
$user->username = "username$i";
|
||||
$user->status = "active";
|
||||
$this->_em->persist($user);
|
||||
|
||||
for ($j = 0; $j < 3; $j++) {;
|
||||
$group = new CmsGroup();
|
||||
$group->name = "group$j";
|
||||
$user->addGroup($group);
|
||||
$this->_em->persist($group);
|
||||
}
|
||||
}
|
||||
$this->_em->flush();
|
||||
}
|
||||
}
|
|
@ -599,4 +599,24 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertEquals(3, count($users));
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1651
|
||||
*/
|
||||
public function testSetParameterBindingSingleIdentifierObjectConverted()
|
||||
{
|
||||
$userC = new CmsUser;
|
||||
$userC->name = 'Jonathan';
|
||||
$userC->username = 'jwage';
|
||||
$userC->status = 'developer';
|
||||
$this->_em->persist($userC);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$q = $this->_em->createQuery("SELECT DISTINCT u from Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1");
|
||||
$q->setParameter(1, $userC);
|
||||
|
||||
$this->assertEquals($userC->id, $q->getParameter(1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,12 @@ class ReadOnlyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\ReadOnlyEntity'),
|
||||
));
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\ReadOnlyEntity'),
|
||||
));
|
||||
} catch(\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
public function testReadOnlyEntityNeverChangeTracked()
|
||||
|
@ -36,6 +39,36 @@ class ReadOnlyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertEquals("Test1", $dbReadOnly->name);
|
||||
$this->assertEquals(1234, $dbReadOnly->numericValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1659
|
||||
*/
|
||||
public function testClearReadOnly()
|
||||
{
|
||||
$readOnly = new ReadOnlyEntity("Test1", 1234);
|
||||
$this->_em->persist($readOnly);
|
||||
$this->_em->flush();
|
||||
$this->_em->getUnitOfWork()->markReadOnly($readOnly);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$this->assertFalse($this->_em->getUnitOfWork()->isReadOnly($readOnly));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1659
|
||||
*/
|
||||
public function testClearEntitiesReadOnly()
|
||||
{
|
||||
$readOnly = new ReadOnlyEntity("Test1", 1234);
|
||||
$this->_em->persist($readOnly);
|
||||
$this->_em->flush();
|
||||
$this->_em->getUnitOfWork()->markReadOnly($readOnly);
|
||||
|
||||
$this->_em->clear(get_class($readOnly));
|
||||
|
||||
$this->assertFalse($this->_em->getUnitOfWork()->isReadOnly($readOnly));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,4 +91,4 @@ class ReadOnlyEntity
|
|||
$this->name = $name;
|
||||
$this->numericValue = $number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use Doctrine\ORM\Proxy\ProxyFactory;
|
|||
use Doctrine\ORM\Proxy\ProxyClassGenerator;
|
||||
use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
|
||||
use Doctrine\Tests\Models\ECommerce\ECommerceShipping;
|
||||
use Doctrine\Tests\Models\Company\CompanyAuction;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
|
@ -39,6 +40,18 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
return $product->getId();
|
||||
}
|
||||
|
||||
public function createAuction()
|
||||
{
|
||||
$event = new CompanyAuction();
|
||||
$event->setData('Doctrine Cookbook');
|
||||
$this->_em->persist($event);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
return $event->getId();
|
||||
}
|
||||
|
||||
public function testLazyLoadsFieldValuesFromDatabase()
|
||||
{
|
||||
$id = $this->createProduct();
|
||||
|
@ -161,6 +174,21 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertFalse($entity->__isInitialized__, "Getting the identifier doesn't initialize the proxy.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1625
|
||||
*/
|
||||
public function testDoNotInitializeProxyOnGettingTheIdentifier_DDC_1625()
|
||||
{
|
||||
$id = $this->createAuction();
|
||||
|
||||
/* @var $entity Doctrine\Tests\Models\Company\CompanyAuction */
|
||||
$entity = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyAuction' , $id);
|
||||
|
||||
$this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy.");
|
||||
$this->assertEquals($id, $entity->getId());
|
||||
$this->assertFalse($entity->__isInitialized__, "Getting the identifier doesn't initialize the proxy when extending.");
|
||||
}
|
||||
|
||||
public function testDoNotInitializeProxyOnGettingTheIdentifierAndReturnTheRightType()
|
||||
{
|
||||
$product = new ECommerceProduct();
|
||||
|
@ -195,4 +223,28 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertEquals('Doctrine Cookbook', $entity->getName());
|
||||
$this->assertTrue($entity->__isInitialized__, "Getting something other than the identifier initializes the proxy.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1604
|
||||
*/
|
||||
public function testCommonPersistenceProxy()
|
||||
{
|
||||
$id = $this->createProduct();
|
||||
|
||||
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
|
||||
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
|
||||
$className = \Doctrine\Common\Util\ClassUtils::getClass($entity);
|
||||
|
||||
$this->assertInstanceOf('Doctrine\Common\Persistence\Proxy', $entity);
|
||||
$this->assertFalse($entity->__isInitialized());
|
||||
$this->assertEquals('Doctrine\Tests\Models\ECommerce\ECommerceProduct', $className);
|
||||
|
||||
$restName = str_replace($this->_em->getConfiguration()->getProxyNamespace(), "", get_class($entity));
|
||||
$restName = substr(get_class($entity), strlen($this->_em->getConfiguration()->getProxyNamespace()) +1);
|
||||
$proxyFileName = $this->_em->getConfiguration()->getProxyDir() . DIRECTORY_SEPARATOR . str_replace("\\", "", $restName) . ".php";
|
||||
$this->assertTrue(file_exists($proxyFileName), "Proxy file name cannot be found generically.");
|
||||
|
||||
$entity->__load();
|
||||
$this->assertTrue($entity->__isInitialized());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,4 +64,31 @@ class MySqlSchemaToolTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertEquals(1, count($sql));
|
||||
$this->assertEquals("CREATE TABLE boolean_model (id INT AUTO_INCREMENT NOT NULL, booleanField TINYINT(1) NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB", $sql[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DBAL-204
|
||||
*/
|
||||
public function testGetCreateSchemaSql4()
|
||||
{
|
||||
$classes = array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\MysqlSchemaNamespacedEntity')
|
||||
);
|
||||
|
||||
$tool = new SchemaTool($this->_em);
|
||||
$sql = $tool->getCreateSchemaSql($classes);
|
||||
|
||||
$this->assertEquals(0, count($sql));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table("namespace.entity")
|
||||
*/
|
||||
class MysqlSchemaNamespacedEntity
|
||||
{
|
||||
/** @Column(type="integer") @Id @GeneratedValue */
|
||||
public $id;
|
||||
}
|
||||
|
||||
|
|
50
tests/Doctrine/Tests/ORM/Functional/SchemaValidatorTest.php
Normal file
50
tests/Doctrine/Tests/ORM/Functional/SchemaValidatorTest.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\ORM\Tools\SchemaValidator;
|
||||
|
||||
/**
|
||||
* Test the validity of all modelsets
|
||||
*
|
||||
* @group DDC-1601
|
||||
*/
|
||||
class SchemaValidatorTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
static public function dataValidateModelSets()
|
||||
{
|
||||
$modelSets = array();
|
||||
foreach (self::$_modelSets as $modelSet => $classes) {
|
||||
if ($modelSet == "customtype") {
|
||||
continue;
|
||||
}
|
||||
$modelSets[] = array($modelSet);
|
||||
}
|
||||
return $modelSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataValidateModelSets
|
||||
*/
|
||||
public function testValidateModelSets($modelSet)
|
||||
{
|
||||
$validator = new SchemaValidator($this->_em);
|
||||
|
||||
$classes = array();
|
||||
foreach (self::$_modelSets[$modelSet] as $className) {
|
||||
$classes[] = $this->_em->getClassMetadata($className);
|
||||
}
|
||||
|
||||
foreach ($classes as $class) {
|
||||
$ce = $validator->validateClass($class);
|
||||
|
||||
foreach ($ce as $key => $error) {
|
||||
if (strpos($error, "must be private or protected. Public fields may break lazy-loading.") !== false) {
|
||||
unset($ce[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertEquals(0, count($ce), "Invalid Modelset: " . $modelSet . " class " . $class->name . ": ". implode("\n", $ce));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -433,4 +433,32 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertEquals($this->article1->id(), $refRep->source()->id());
|
||||
$this->assertEquals($this->article2->id(), $refRep->target()->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1652
|
||||
*/
|
||||
public function testArrayHydrationWithCompositeKey()
|
||||
{
|
||||
$dql = "SELECT r,s,t FROM Doctrine\Tests\Models\DDC117\DDC117Reference r INNER JOIN r.source s INNER JOIN r.target t";
|
||||
$before = count($this->_em->createQuery($dql)->getResult());
|
||||
|
||||
$this->article1 = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Article", $this->article1->id());
|
||||
$this->article2 = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Article", $this->article2->id());
|
||||
|
||||
$this->reference = new DDC117Reference($this->article2, $this->article1, "Test-Description");
|
||||
$this->_em->persist($this->reference);
|
||||
|
||||
$this->reference = new DDC117Reference($this->article1, $this->article1, "Test-Description");
|
||||
$this->_em->persist($this->reference);
|
||||
|
||||
$this->reference = new DDC117Reference($this->article2, $this->article2, "Test-Description");
|
||||
$this->_em->persist($this->reference);
|
||||
|
||||
$this->_em->flush();
|
||||
|
||||
$dql = "SELECT r,s,t FROM Doctrine\Tests\Models\DDC117\DDC117Reference r INNER JOIN r.source s INNER JOIN r.target t";
|
||||
$data = $this->_em->createQuery($dql)->getArrayResult();
|
||||
|
||||
$this->assertEquals($before + 3, count($data));
|
||||
}
|
||||
}
|
||||
|
|
67
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1526Test.php
Normal file
67
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1526Test.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
/**
|
||||
* @group DDC-1526
|
||||
*/
|
||||
class DDC1526Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1526Menu'),
|
||||
));
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$parents = array();
|
||||
for ($i = 0; $i < 9; $i++) {
|
||||
$entity = new DDC1526Menu;
|
||||
|
||||
if (isset ($parents[($i % 3)])) {
|
||||
$entity->parent = $parents[($i%3)];
|
||||
}
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$parents[$i] = $entity;
|
||||
}
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$dql = "SELECT m, c
|
||||
FROM " . __NAMESPACE__ . "\DDC1526Menu m
|
||||
LEFT JOIN m.children c";
|
||||
$menus = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
// All Children collection now have to be initiailzed
|
||||
foreach ($menus as $menu) {
|
||||
$this->assertTrue($menu->children->isInitialized());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1526Menu
|
||||
{
|
||||
/**
|
||||
* @Column(type="integer")
|
||||
* @Id
|
||||
* @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC1526Menu", inversedBy="children")
|
||||
*/
|
||||
public $parent;
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity="DDC1526Menu", mappedBy="parent")
|
||||
*/
|
||||
public $children;
|
||||
}
|
45
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1594Test.php
Normal file
45
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1594Test.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
use Doctrine\Tests\Models\CMS\CmsComment;
|
||||
use Doctrine\Tests\Models\CMS\CmsArticle;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
|
||||
/**
|
||||
* @group DDC-1594
|
||||
*/
|
||||
class DDC1594Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$user = new CmsUser();
|
||||
$user->status = 'foo';
|
||||
$user->username = 'foo';
|
||||
$user->name = 'foo';
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->clear();
|
||||
$detachedUser = clone $user;
|
||||
$detachedUser->name = 'bar';
|
||||
$detachedUser->status = 'bar';
|
||||
|
||||
$newUser = $this->_em->getReference(get_class($user), $user->id);
|
||||
|
||||
$mergedUser = $this->_em->merge($detachedUser);
|
||||
|
||||
$this->assertNotSame($mergedUser, $detachedUser);
|
||||
$this->assertEquals('bar', $detachedUser->getName());
|
||||
$this->assertEquals('bar', $mergedUser->getName());
|
||||
}
|
||||
}
|
111
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1595Test.php
Normal file
111
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1595Test.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
/**
|
||||
* @group DDC-1595
|
||||
* @group DDC-1596
|
||||
*/
|
||||
class DDC1595Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\DebugStack);
|
||||
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1595BaseInheritance'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1595InheritedEntity1'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1595InheritedEntity2'),
|
||||
));
|
||||
}
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$e1 = new DDC1595InheritedEntity1();
|
||||
|
||||
$this->_em->persist($e1);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$sqlLogger = $this->_em->getConnection()->getConfiguration()->getSQLLogger();
|
||||
$repository = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1595InheritedEntity1');
|
||||
|
||||
$entity1 = $repository->find($e1->id);
|
||||
|
||||
// DDC-1596
|
||||
$this->assertEquals(
|
||||
"SELECT t0.id AS id1, t0.type FROM base t0 WHERE t0.id = ? AND t0.type IN ('Entity1')",
|
||||
$sqlLogger->queries[count($sqlLogger->queries)]['sql']
|
||||
);
|
||||
|
||||
$entities = $entity1->getEntities()->getValues();
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT t0.id AS id1, t0.type FROM base t0 INNER JOIN entity1_entity2 ON t0.id = entity1_entity2.item WHERE entity1_entity2.parent = ? AND t0.type IN ('Entity2')",
|
||||
$sqlLogger->queries[count($sqlLogger->queries)]['sql']
|
||||
);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$entity1 = $repository->find($e1->id);
|
||||
$entities = $entity1->getEntities()->count();
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT COUNT(*) FROM entity1_entity2 t WHERE parent = ?",
|
||||
$sqlLogger->queries[count($sqlLogger->queries)]['sql']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="base")
|
||||
*
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorColumn(name="type", type="string")
|
||||
* @DiscriminatorMap({
|
||||
* "Entity1" = "DDC1595InheritedEntity1",
|
||||
* "Entity2" = "DDC1595InheritedEntity2"
|
||||
* })
|
||||
*/
|
||||
abstract class DDC1595BaseInheritance
|
||||
{
|
||||
/**
|
||||
* @Id @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="entity1")
|
||||
*/
|
||||
class DDC1595InheritedEntity1 extends DDC1595BaseInheritance
|
||||
{
|
||||
/**
|
||||
* @ManyToMany(targetEntity="DDC1595InheritedEntity2", fetch="EXTRA_LAZY")
|
||||
* @JoinTable(name="entity1_entity2",
|
||||
* joinColumns={@JoinColumn(name="parent", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@JoinColumn(name="item", referencedColumnName="id")}
|
||||
* )
|
||||
*/
|
||||
protected $entities;
|
||||
|
||||
public function getEntities()
|
||||
{
|
||||
return $this->entities;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="entity2")
|
||||
*/
|
||||
class DDC1595InheritedEntity2 extends DDC1595BaseInheritance
|
||||
{
|
||||
}
|
121
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1643Test.php
Normal file
121
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1643Test.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\Models\CMS\CmsGroup;
|
||||
|
||||
/**
|
||||
* @group DDC-1643
|
||||
*/
|
||||
class DDC1643Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
private $user1;
|
||||
private $user2;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
|
||||
$user1 = new CmsUser();
|
||||
$user1->username = "beberlei";
|
||||
$user1->name = "Benjamin";
|
||||
$user1->status = "active";
|
||||
$group1 = new CmsGroup();
|
||||
$group1->name = "test";
|
||||
$group2 = new CmsGroup();
|
||||
$group2->name = "test";
|
||||
$user1->addGroup($group1);
|
||||
$user1->addGroup($group2);
|
||||
$user2 = new CmsUser();
|
||||
$user2->username = "romanb";
|
||||
$user2->name = "Roman";
|
||||
$user2->status = "active";
|
||||
|
||||
$this->_em->persist($user1);
|
||||
$this->_em->persist($user2);
|
||||
$this->_em->persist($group1);
|
||||
$this->_em->persist($group2);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$this->user1 = $this->_em->find(get_class($user1), $user1->id);
|
||||
$this->user2 = $this->_em->find(get_class($user1), $user2->id);
|
||||
}
|
||||
|
||||
public function testClonePersistentCollectionAndReuse()
|
||||
{
|
||||
$user1 = $this->user1;
|
||||
|
||||
$user1->groups = clone $user1->groups;
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$user1 = $this->_em->find(get_class($user1), $user1->id);
|
||||
|
||||
$this->assertEquals(2, count($user1->groups));
|
||||
}
|
||||
|
||||
public function testClonePersistentCollectionAndShare()
|
||||
{
|
||||
$user1 = $this->user1;
|
||||
$user2 = $this->user2;
|
||||
|
||||
$user2->groups = clone $user1->groups;
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$user1 = $this->_em->find(get_class($user1), $user1->id);
|
||||
$user2 = $this->_em->find(get_class($user1), $user2->id);
|
||||
|
||||
$this->assertEquals(2, count($user1->groups));
|
||||
$this->assertEquals(2, count($user2->groups));
|
||||
}
|
||||
|
||||
public function testCloneThenDirtyPersistentCollection()
|
||||
{
|
||||
$user1 = $this->user1;
|
||||
$user2 = $this->user2;
|
||||
|
||||
$group3 = new CmsGroup();
|
||||
$group3->name = "test";
|
||||
$user2->groups = clone $user1->groups;
|
||||
$user2->groups->add($group3);
|
||||
|
||||
$this->_em->persist($group3);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$user1 = $this->_em->find(get_class($user1), $user1->id);
|
||||
$user2 = $this->_em->find(get_class($user1), $user2->id);
|
||||
|
||||
$this->assertEquals(3, count($user2->groups));
|
||||
$this->assertEquals(2, count($user1->groups));
|
||||
}
|
||||
|
||||
public function testNotCloneAndPassAroundFlush()
|
||||
{
|
||||
$user1 = $this->user1;
|
||||
$user2 = $this->user2;
|
||||
|
||||
$group3 = new CmsGroup();
|
||||
$group3->name = "test";
|
||||
$user2->groups = $user1->groups;
|
||||
$user2->groups->add($group3);
|
||||
|
||||
$this->assertEQuals(1, count($user1->groups->getInsertDiff()));
|
||||
|
||||
$this->_em->persist($group3);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$user1 = $this->_em->find(get_class($user1), $user1->id);
|
||||
$user2 = $this->_em->find(get_class($user1), $user2->id);
|
||||
|
||||
$this->assertEquals(3, count($user2->groups));
|
||||
$this->assertEquals(3, count($user1->groups));
|
||||
}
|
||||
}
|
||||
|
103
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php
Normal file
103
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
/**
|
||||
* @group DDC-1654
|
||||
*/
|
||||
class DDC1654Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->setUpEntitySchema(array(
|
||||
__NAMESPACE__ . '\\DDC1654Post',
|
||||
__NAMESPACE__ . '\\DDC1654Comment',
|
||||
));
|
||||
}
|
||||
|
||||
public function testManyToManyRemoveFromCollectionOrphanRemoval()
|
||||
{
|
||||
$post = new DDC1654Post();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
|
||||
$this->_em->persist($post);
|
||||
$this->_em->flush();
|
||||
|
||||
$post->comments->remove(0);
|
||||
$post->comments->remove(1);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll();
|
||||
$this->assertEquals(0, count($comments));
|
||||
}
|
||||
|
||||
public function testManyToManyRemoveElementFromCollectionOrphanRemoval()
|
||||
{
|
||||
$post = new DDC1654Post();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
|
||||
$this->_em->persist($post);
|
||||
$this->_em->flush();
|
||||
|
||||
$post->comments->removeElement($post->comments[0]);
|
||||
$post->comments->removeElement($post->comments[1]);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll();
|
||||
$this->assertEquals(0, count($comments));
|
||||
}
|
||||
|
||||
public function testManyToManyClearCollectionOrphanRemoval()
|
||||
{
|
||||
$post = new DDC1654Post();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
$post->comments[] = new DDC1654Comment();
|
||||
|
||||
$this->_em->persist($post);
|
||||
$this->_em->flush();
|
||||
|
||||
$post->comments->clear();
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll();
|
||||
$this->assertEquals(0, count($comments));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1654Post
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer") @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="DDC1654Comment", orphanRemoval=true,
|
||||
* cascade={"persist"})
|
||||
*/
|
||||
public $comments = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1654Comment
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer") @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
}
|
144
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1655Test.php
Normal file
144
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1655Test.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
/**
|
||||
* @group DDC-1655
|
||||
* @group DDC-1640
|
||||
* @group DDC-1556
|
||||
*/
|
||||
class DDC1655Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1655Foo'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1655Bar'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1655Baz'),
|
||||
));
|
||||
} catch(\Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function testPostLoadOneToManyInheritance()
|
||||
{
|
||||
$cm = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1655Foo');
|
||||
$this->assertEquals(array("postLoad" => array("postLoad")), $cm->lifecycleCallbacks);
|
||||
|
||||
$cm = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1655Bar');
|
||||
$this->assertEquals(array("postLoad" => array("postLoad", "postSubLoaded")), $cm->lifecycleCallbacks);
|
||||
|
||||
$baz = new DDC1655Baz();
|
||||
$foo = new DDC1655Foo();
|
||||
$foo->baz = $baz;
|
||||
$bar = new DDC1655Bar();
|
||||
$bar->baz = $baz;
|
||||
|
||||
$this->_em->persist($foo);
|
||||
$this->_em->persist($bar);
|
||||
$this->_em->persist($baz);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$baz = $this->_em->find(get_class($baz), $baz->id);
|
||||
foreach ($baz->foos as $foo) {
|
||||
$this->assertEquals(1, $foo->loaded, "should have loaded callback counter incremented for " . get_class($foo));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that post load is not executed several times when the entity
|
||||
* is rehydrated again although its already known.
|
||||
*/
|
||||
public function testPostLoadInheritanceChild()
|
||||
{
|
||||
$bar = new DDC1655Bar();
|
||||
|
||||
$this->_em->persist($bar);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$bar = $this->_em->find(get_class($bar), $bar->id);
|
||||
$this->assertEquals(1, $bar->loaded);
|
||||
$this->assertEquals(1, $bar->subLoaded);
|
||||
|
||||
$bar = $this->_em->find(get_class($bar), $bar->id);
|
||||
$this->assertEquals(1, $bar->loaded);
|
||||
$this->assertEquals(1, $bar->subLoaded);
|
||||
|
||||
$dql = "SELECT b FROM " . __NAMESPACE__ . "\DDC1655Bar b WHERE b.id = ?1";
|
||||
$bar = $this->_em->createQuery($dql)->setParameter(1, $bar->id)->getSingleResult();
|
||||
|
||||
$this->assertEquals(1, $bar->loaded);
|
||||
$this->assertEquals(1, $bar->subLoaded);
|
||||
|
||||
$this->_em->refresh($bar);
|
||||
|
||||
$this->assertEquals(2, $bar->loaded);
|
||||
$this->assertEquals(2, $bar->subLoaded);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorMap({
|
||||
* "foo" = "DDC1655Foo",
|
||||
* "bar" = "DDC1655Bar"
|
||||
* })
|
||||
* @HasLifecycleCallbacks
|
||||
*/
|
||||
class DDC1655Foo
|
||||
{
|
||||
/** @Id @GeneratedValue @Column(type="integer") */
|
||||
public $id;
|
||||
|
||||
public $loaded = 0;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC1655Baz", inversedBy="foos")
|
||||
*/
|
||||
public $baz;
|
||||
|
||||
/**
|
||||
* @PostLoad
|
||||
*/
|
||||
public function postLoad()
|
||||
{
|
||||
$this->loaded++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @HasLifecycleCallbacks
|
||||
*/
|
||||
class DDC1655Bar extends DDC1655Foo
|
||||
{
|
||||
public $subLoaded;
|
||||
|
||||
/**
|
||||
* @PostLoad
|
||||
*/
|
||||
public function postSubLoaded()
|
||||
{
|
||||
$this->subLoaded++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1655Baz
|
||||
{
|
||||
/** @Id @GeneratedValue @Column(type="integer") */
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity="DDC1655Foo", mappedBy="baz")
|
||||
*/
|
||||
public $foos = array();
|
||||
}
|
120
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC657Test.php
Normal file
120
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC657Test.php
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
use Doctrine\Tests\Models\Generic\DateTimeModel;
|
||||
|
||||
/**
|
||||
* @group DDC-657
|
||||
*/
|
||||
class DDC657Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
const NS = 'Doctrine\Tests\Models\Generic';
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->useModelSet('generic');
|
||||
parent::setUp();
|
||||
|
||||
$this->loadFixtures();
|
||||
}
|
||||
|
||||
public function testEntitySingleResult()
|
||||
{
|
||||
$query = $this->_em->createQuery('SELECT d FROM ' . self::NS . '\DateTimeModel d');
|
||||
$datetime = $query->setMaxResults(1)->getSingleResult();
|
||||
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Generic\DateTimeModel', $datetime);
|
||||
|
||||
$this->assertInstanceOf('DateTime', $datetime->datetime);
|
||||
$this->assertInstanceOf('DateTime', $datetime->time);
|
||||
$this->assertInstanceOf('DateTime', $datetime->date);
|
||||
}
|
||||
|
||||
public function testScalarResult()
|
||||
{
|
||||
$query = $this->_em->createQuery('SELECT d.id, d.time, d.date, d.datetime FROM ' . self::NS . '\DateTimeModel d ORDER BY d.date ASC');
|
||||
$result = $query->getScalarResult();
|
||||
|
||||
$this->assertCount(2,$result);
|
||||
|
||||
$this->assertContains('11:11:11', $result[0]['time']);
|
||||
$this->assertContains('2010-01-01', $result[0]['date']);
|
||||
$this->assertContains('2010-01-01 11:11:11', $result[0]['datetime']);
|
||||
|
||||
$this->assertContains('12:12:12', $result[1]['time']);
|
||||
$this->assertContains('2010-02-02', $result[1]['date']);
|
||||
$this->assertContains('2010-02-02 12:12:12', $result[1]['datetime']);
|
||||
}
|
||||
|
||||
public function testaTicketEntityArrayResult()
|
||||
{
|
||||
$query = $this->_em->createQuery('SELECT d FROM ' . self::NS . '\DateTimeModel d ORDER BY d.date ASC');
|
||||
$result = $query->getArrayResult();
|
||||
|
||||
$this->assertCount(2,$result);
|
||||
|
||||
$this->assertInstanceOf('DateTime', $result[0]['datetime']);
|
||||
$this->assertInstanceOf('DateTime', $result[0]['time']);
|
||||
$this->assertInstanceOf('DateTime', $result[0]['date']);
|
||||
|
||||
$this->assertInstanceOf('DateTime', $result[1]['datetime']);
|
||||
$this->assertInstanceOf('DateTime', $result[1]['time']);
|
||||
$this->assertInstanceOf('DateTime', $result[1]['date']);
|
||||
}
|
||||
|
||||
public function testTicketSingleResult()
|
||||
{
|
||||
$query = $this->_em->createQuery('SELECT d.id, d.time, d.date, d.datetime FROM ' . self::NS . '\DateTimeModel d ORDER BY d.date ASC');
|
||||
$datetime = $query->setMaxResults(1)->getSingleResult();
|
||||
|
||||
$this->assertTrue(is_array($datetime));
|
||||
|
||||
$this->assertInstanceOf('DateTime', $datetime['datetime']);
|
||||
$this->assertInstanceOf('DateTime', $datetime['time']);
|
||||
$this->assertInstanceOf('DateTime', $datetime['date']);
|
||||
}
|
||||
|
||||
public function testTicketResult()
|
||||
{
|
||||
$query = $this->_em->createQuery('SELECT d.id, d.time, d.date, d.datetime FROM ' . self::NS . '\DateTimeModel d ORDER BY d.date ASC');
|
||||
$result = $query->getResult();
|
||||
|
||||
$this->assertCount(2,$result);
|
||||
|
||||
$this->assertInstanceOf('DateTime', $result[0]['time']);
|
||||
$this->assertInstanceOf('DateTime', $result[0]['date']);
|
||||
$this->assertInstanceOf('DateTime', $result[0]['datetime']);
|
||||
|
||||
$this->assertEquals('2010-01-01 11:11:11', $result[0]['datetime']->format('Y-m-d G:i:s'));
|
||||
|
||||
$this->assertInstanceOf('DateTime', $result[1]['time']);
|
||||
$this->assertInstanceOf('DateTime', $result[1]['date']);
|
||||
$this->assertInstanceOf('DateTime', $result[1]['datetime']);
|
||||
|
||||
$this->assertEquals('2010-02-02 12:12:12', $result[1]['datetime']->format('Y-m-d G:i:s'));
|
||||
}
|
||||
|
||||
public function loadFixtures()
|
||||
{
|
||||
$timezone = new \DateTimeZone('America/Sao_Paulo');
|
||||
|
||||
$dateTime1 = new DateTimeModel();
|
||||
$dateTime2 = new DateTimeModel();
|
||||
|
||||
$dateTime1->date = new \DateTime('2010-01-01', $timezone);
|
||||
$dateTime1->time = new \DateTime('2010-01-01 11:11:11', $timezone);
|
||||
$dateTime1->datetime= new \DateTime('2010-01-01 11:11:11', $timezone);
|
||||
|
||||
$dateTime2->date = new \DateTime('2010-02-02', $timezone);
|
||||
$dateTime2->time = new \DateTime('2010-02-02 12:12:12', $timezone);
|
||||
$dateTime2->datetime= new \DateTime('2010-02-02 12:12:12', $timezone);
|
||||
|
||||
$this->_em->persist($dateTime1);
|
||||
$this->_em->persist($dateTime2);
|
||||
|
||||
$this->_em->flush();
|
||||
}
|
||||
}
|
|
@ -8,6 +8,9 @@ require_once __DIR__ . '/../../../TestInit.php';
|
|||
|
||||
class DDC742Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
private $userCm;
|
||||
private $commentCm;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
@ -15,6 +18,7 @@ class DDC742Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
if (\extension_loaded('memcache')) {
|
||||
$memcache = new \Memcache();
|
||||
$memcache->addServer('localhost');
|
||||
$memcache->flush();
|
||||
|
||||
$cacheDriver = new \Doctrine\Common\Cache\MemcacheCache();
|
||||
$cacheDriver->setMemcache($memcache);
|
||||
|
@ -123,4 +127,4 @@ class DDC742Comment
|
|||
* @var string
|
||||
*/
|
||||
public $content;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,43 @@ class TypeValueSqlTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||
$this->assertEquals('FOO', $this->_em->getConnection()->fetchColumn("select lowerCaseString from customtype_uppercases where id=".$entity->id.""), 'Database holds uppercase string');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1642
|
||||
*/
|
||||
public function testUpperCaseStringTypeWhenColumnNameIsDefined()
|
||||
{
|
||||
|
||||
$entity = new CustomTypeUpperCase();
|
||||
$entity->lowerCaseString = 'Some Value';
|
||||
$entity->namedLowerCaseString = 'foo';
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
|
||||
$id = $entity->id;
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$entity = $this->_em->find('\Doctrine\Tests\Models\CustomType\CustomTypeUpperCase', $id);
|
||||
$this->assertEquals('foo', $entity->namedLowerCaseString, 'Entity holds lowercase string');
|
||||
$this->assertEquals('FOO', $this->_em->getConnection()->fetchColumn("select named_lower_case_string from customtype_uppercases where id=".$entity->id.""), 'Database holds uppercase string');
|
||||
|
||||
|
||||
$entity->namedLowerCaseString = 'bar';
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
|
||||
$id = $entity->id;
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$entity = $this->_em->find('\Doctrine\Tests\Models\CustomType\CustomTypeUpperCase', $id);
|
||||
$this->assertEquals('bar', $entity->namedLowerCaseString, 'Entity holds lowercase string');
|
||||
$this->assertEquals('BAR', $this->_em->getConnection()->fetchColumn("select named_lower_case_string from customtype_uppercases where id=".$entity->id.""), 'Database holds uppercase string');
|
||||
}
|
||||
|
||||
public function testTypeValueSqlWithAssociations()
|
||||
{
|
||||
$parent = new CustomTypeParent();
|
||||
|
|
|
@ -77,6 +77,21 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
|||
* @depends testEntityTableNameAndInheritance
|
||||
* @param ClassMetadata $class
|
||||
*/
|
||||
public function testEntityOptions($class)
|
||||
{
|
||||
$this->assertArrayHasKey('options', $class->table, 'ClassMetadata should have options key in table property.');
|
||||
|
||||
$this->assertEquals(array(
|
||||
'foo' => 'bar', 'baz' => array('key' => 'val')
|
||||
), $class->table['options']);
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testEntityOptions
|
||||
* @param ClassMetadata $class
|
||||
*/
|
||||
public function testEntitySequence($class)
|
||||
{
|
||||
$this->assertInternalType('array', $class->sequenceGeneratorDefinition, 'No Sequence Definition set on this driver.');
|
||||
|
@ -141,6 +156,9 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
|||
$this->assertTrue($class->fieldMappings['name']['nullable']);
|
||||
$this->assertTrue($class->fieldMappings['name']['unique']);
|
||||
|
||||
$expected = array('foo' => 'bar', 'baz' => array('key' => 'val'));
|
||||
$this->assertEquals($expected, $class->fieldMappings['name']['options']);
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
|
@ -428,6 +446,21 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
|||
$this->assertEquals('NAME', $class->columnNames['name']);
|
||||
$this->assertEquals('DDC1476ENTITY_WITH_DEFAULT_FIELD_TYPE', $class->table['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-807
|
||||
* @group DDC-553
|
||||
*/
|
||||
public function testDiscriminatorColumnDefinition()
|
||||
{
|
||||
$class = $this->createClassMetadata(__NAMESPACE__ . '\DDC807Entity');
|
||||
|
||||
$this->assertArrayHasKey('columnDefinition', $class->discriminatorColumn);
|
||||
$this->assertArrayHasKey('name', $class->discriminatorColumn);
|
||||
|
||||
$this->assertEquals("ENUM('ONE','TWO')", $class->discriminatorColumn['columnDefinition']);
|
||||
$this->assertEquals("dtype", $class->discriminatorColumn['name']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -436,7 +469,8 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
|||
* @Table(
|
||||
* name="cms_users",
|
||||
* uniqueConstraints={@UniqueConstraint(name="search_idx", columns={"name", "user_email"})},
|
||||
* indexes={@Index(name="name_idx", columns={"name"}), @Index(name="0", columns={"user_email"})}
|
||||
* indexes={@Index(name="name_idx", columns={"name"}), @Index(name="0", columns={"user_email"})},
|
||||
* options={"foo": "bar", "baz": {"key": "val"}}
|
||||
* )
|
||||
*/
|
||||
class User
|
||||
|
@ -450,7 +484,7 @@ class User
|
|||
public $id;
|
||||
|
||||
/**
|
||||
* @Column(length=50, nullable=true, unique=true)
|
||||
* @Column(length=50, nullable=true, unique=true, options={"foo": "bar", "baz": {"key": "val"}})
|
||||
*/
|
||||
public $name;
|
||||
|
||||
|
@ -507,6 +541,7 @@ class User
|
|||
$metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE);
|
||||
$metadata->setPrimaryTable(array(
|
||||
'name' => 'cms_users',
|
||||
'options' => array('foo' => 'bar', 'baz' => array('key' => 'val')),
|
||||
));
|
||||
$metadata->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT);
|
||||
$metadata->addLifecycleCallback('doStuffOnPrePersist', 'prePersist');
|
||||
|
@ -525,6 +560,7 @@ class User
|
|||
'unique' => true,
|
||||
'nullable' => true,
|
||||
'columnName' => 'name',
|
||||
'options' => array('foo' => 'bar', 'baz' => array('key' => 'val')),
|
||||
));
|
||||
$metadata->mapField(array(
|
||||
'fieldName' => 'email',
|
||||
|
@ -717,6 +753,42 @@ class DDC1170Entity
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorMap({"ONE" = "DDC807SubClasse1", "TWO" = "DDC807SubClasse2"})
|
||||
* @DiscriminatorColumn(name = "dtype", columnDefinition="ENUM('ONE','TWO')")
|
||||
*/
|
||||
class DDC807Entity
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue(strategy="NONE")
|
||||
**/
|
||||
public $id;
|
||||
|
||||
public static function loadMetadata(ClassMetadataInfo $metadata)
|
||||
{
|
||||
$metadata->mapField(array(
|
||||
'id' => true,
|
||||
'fieldName' => 'id',
|
||||
));
|
||||
|
||||
$metadata->setDiscriminatorColumn(array(
|
||||
'name' => "dtype",
|
||||
'type' => "string",
|
||||
'columnDefinition' => "ENUM('ONE','TWO')"
|
||||
));
|
||||
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DDC807SubClasse1 {}
|
||||
class DDC807SubClasse2 {}
|
||||
|
||||
class Address {}
|
||||
class Phonenumber {}
|
||||
class Group {}
|
||||
|
|
|
@ -377,6 +377,7 @@ class ClassMetadataBuilderTest extends \Doctrine\Tests\OrmTestCase
|
|||
array(
|
||||
'user_id' => 'id',
|
||||
),
|
||||
'orphanRemoval' => false,
|
||||
),
|
||||
), $this->cm->associationMappings);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@ require_once __DIR__ . '/../../TestInit.php';
|
|||
|
||||
class ClassMetadataLoadEventTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
/**
|
||||
* @group DDC-1610
|
||||
*/
|
||||
public function testEvent()
|
||||
{
|
||||
$em = $this->_getTestEntityManager();
|
||||
|
@ -17,6 +20,8 @@ class ClassMetadataLoadEventTest extends \Doctrine\Tests\OrmTestCase
|
|||
$evm->addEventListener(Events::loadClassMetadata, $this);
|
||||
$classMetadata = $metadataFactory->getMetadataFor('Doctrine\Tests\ORM\Mapping\LoadEventTestEntity');
|
||||
$this->assertTrue($classMetadata->hasField('about'));
|
||||
$this->assertArrayHasKey('about', $classMetadata->reflFields);
|
||||
$this->assertInstanceOf('ReflectionProperty', $classMetadata->reflFields['about']);
|
||||
}
|
||||
|
||||
public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs)
|
||||
|
@ -48,4 +53,4 @@ class LoadEventTestEntity
|
|||
private $name;
|
||||
|
||||
private $about;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -595,4 +595,61 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
|
|||
$this->setExpectedException("Doctrine\ORM\Mapping\MappingException", "The target-entity Doctrine\Tests\Models\CMS\UnknownClass cannot be found in 'Doctrine\Tests\Models\CMS\CmsUser#address'.");
|
||||
$cm->validateAssocations();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Doctrine\ORM\Mapping\MappingException
|
||||
* @expectedExceptionMessage Discriminator column name on entity class 'Doctrine\Tests\Models\CMS\CmsUser' is not defined.
|
||||
*/
|
||||
public function testNameIsMandatoryForDiscriminatorColumnsMappingException()
|
||||
{
|
||||
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
$cm->setDiscriminatorColumn(array());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-984
|
||||
* @group DDC-559
|
||||
* @group DDC-1575
|
||||
*/
|
||||
public function testFullyQualifiedClassNameShouldBeGivenToNamingStrategy()
|
||||
{
|
||||
$namingStrategy = new MyNamespacedNamingStrategy();
|
||||
$addressMetadata = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', $namingStrategy);
|
||||
$articleMetadata = new ClassMetadata('DoctrineGlobal_Article', $namingStrategy);
|
||||
$routingMetadata = new ClassMetadata('Doctrine\Tests\Models\Routing\RoutingLeg',$namingStrategy);
|
||||
|
||||
$addressMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
$articleMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
$routingMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
|
||||
$addressMetadata->mapManyToMany(array(
|
||||
'fieldName' => 'user',
|
||||
'targetEntity' => 'CmsUser'
|
||||
));
|
||||
|
||||
$articleMetadata->mapManyToMany(array(
|
||||
'fieldName' => 'author',
|
||||
'targetEntity' => 'Doctrine\Tests\Models\CMS\CmsUser'
|
||||
));
|
||||
|
||||
$this->assertEquals('routing_routingleg', $routingMetadata->table['name']);
|
||||
$this->assertEquals('cms_cmsaddress_cms_cmsuser', $addressMetadata->associationMappings['user']['joinTable']['name']);
|
||||
$this->assertEquals('doctrineglobal_article_cms_cmsuser', $articleMetadata->associationMappings['author']['joinTable']['name']);
|
||||
}
|
||||
}
|
||||
|
||||
class MyNamespacedNamingStrategy extends \Doctrine\ORM\Mapping\DefaultNamingStrategy
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function classToTableName($className)
|
||||
{
|
||||
if (strpos($className, '\\') !== false) {
|
||||
$className = str_replace('\\', '_', str_replace('Doctrine\Tests\Models\\', '', $className));
|
||||
}
|
||||
|
||||
return strtolower($className);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,42 @@ class DriverChainTest extends \Doctrine\Tests\OrmTestCase
|
|||
$this->assertTrue($chain->isTransient('stdClass'), "stdClass isTransient");
|
||||
$this->assertFalse($chain->isTransient('Doctrine\Tests\Models\CMS\CmsUser'), "CmsUser is not Transient");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1412
|
||||
*/
|
||||
public function testDefaultDriver()
|
||||
{
|
||||
$companyDriver = $this->getMock('Doctrine\ORM\Mapping\Driver\Driver');
|
||||
$dafaultDriver = $this->getMock('Doctrine\ORM\Mapping\Driver\Driver');
|
||||
$entityClassName = 'Doctrine\Tests\ORM\Mapping\DriverChainEntity';
|
||||
$managerClassName = 'Doctrine\Tests\Models\Company\CompanyManager';
|
||||
$chain = new DriverChain();
|
||||
|
||||
$companyDriver->expects($this->never())
|
||||
->method('loadMetadataForClass');
|
||||
$companyDriver->expects($this->once())
|
||||
->method('isTransient')
|
||||
->with($this->equalTo($managerClassName))
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$dafaultDriver->expects($this->never())
|
||||
->method('loadMetadataForClass');
|
||||
$dafaultDriver->expects($this->once())
|
||||
->method('isTransient')
|
||||
->with($this->equalTo($entityClassName))
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->assertNull($chain->getDefaultDriver());
|
||||
|
||||
$chain->setDefaultDriver($dafaultDriver);
|
||||
$chain->addDriver($companyDriver, 'Doctrine\Tests\Models\Company');
|
||||
|
||||
$this->assertSame($dafaultDriver, $chain->getDefaultDriver());
|
||||
|
||||
$this->assertTrue($chain->isTransient($entityClassName));
|
||||
$this->assertFalse($chain->isTransient($managerClassName));
|
||||
}
|
||||
}
|
||||
|
||||
class DriverChainEntity
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
|
||||
$metadata->mapField(array(
|
||||
'id' => true,
|
||||
'fieldName' => 'id',
|
||||
));
|
||||
|
||||
$metadata->setDiscriminatorColumn(array(
|
||||
'name' => "dtype",
|
||||
'columnDefinition' => "ENUM('ONE','TWO')"
|
||||
));
|
||||
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE);
|
|
@ -27,6 +27,7 @@ $metadata->mapField(array(
|
|||
'unique' => true,
|
||||
'nullable' => true,
|
||||
'columnName' => 'name',
|
||||
'options' => array('foo' => 'bar', 'baz' => array('key' => 'val')),
|
||||
));
|
||||
$metadata->mapField(array(
|
||||
'fieldName' => 'email',
|
||||
|
@ -106,6 +107,10 @@ $metadata->mapManyToMany(array(
|
|||
),
|
||||
'orderBy' => NULL,
|
||||
));
|
||||
$metadata->table['options'] = array(
|
||||
'foo' => 'bar',
|
||||
'baz' => array('key' => 'val')
|
||||
);
|
||||
$metadata->table['uniqueConstraints'] = array(
|
||||
'search_idx' => array('columns' => array('name', 'user_email')),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\ORM\Mapping\DDC807Entity" inheritance-type="SINGLE_TABLE">
|
||||
<id name="id">
|
||||
<generator strategy="NONE"/>
|
||||
</id>
|
||||
|
||||
<discriminator-column name="dtype" column-definition="ENUM('ONE','TWO')"/>
|
||||
|
||||
<discriminator-map>
|
||||
<discriminator-mapping value="ONE" class="DDC807SubClasse1" />
|
||||
<discriminator-mapping value="TWO" class="DDC807SubClasse1" />
|
||||
</discriminator-map>
|
||||
</entity>
|
||||
|
||||
</doctrine-mapping>
|
|
@ -6,6 +6,12 @@
|
|||
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\ORM\Mapping\User" table="cms_users">
|
||||
<options>
|
||||
<option name="foo">bar</option>
|
||||
<option name="baz">
|
||||
<option name="key">val</option>
|
||||
</option>
|
||||
</options>
|
||||
|
||||
<indexes>
|
||||
<index name="name_idx" columns="name"/>
|
||||
|
@ -15,7 +21,7 @@
|
|||
<unique-constraints>
|
||||
<unique-constraint columns="name,user_email" name="search_idx" />
|
||||
</unique-constraints>
|
||||
|
||||
|
||||
<lifecycle-callbacks>
|
||||
<lifecycle-callback type="prePersist" method="doStuffOnPrePersist"/>
|
||||
<lifecycle-callback type="prePersist" method="doOtherStuffOnPrePersistToo"/>
|
||||
|
@ -31,7 +37,14 @@
|
|||
<sequence-generator sequence-name="tablename_seq" allocation-size="100" initial-value="1" />
|
||||
</id>
|
||||
|
||||
<field name="name" column="name" type="string" length="50" nullable="true" unique="true" />
|
||||
<field name="name" column="name" type="string" length="50" nullable="true" unique="true">
|
||||
<options>
|
||||
<option name="foo">bar</option>
|
||||
<option name="baz">
|
||||
<option name="key">val</option>
|
||||
</option>
|
||||
</options>
|
||||
</field>
|
||||
<field name="email" column="user_email" type="string" column-definition="CHAR(32) NOT NULL" />
|
||||
|
||||
<one-to-one field="address" target-entity="Address" inversed-by="user">
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
Doctrine\Tests\ORM\Mapping\DDC807Entity:
|
||||
type: entity
|
||||
inheritanceType: SINGLE_TABLE
|
||||
discriminatorMap:
|
||||
ONE: DDC807SubClasse1
|
||||
TWO: DDC807SubClasse2
|
||||
discriminatorColumn:
|
||||
name: dtype
|
||||
columnDefinition: ENUM('ONE','TWO')
|
||||
id:
|
||||
id:
|
||||
generator:
|
||||
strategy: NONE
|
|
@ -1,6 +1,10 @@
|
|||
Doctrine\Tests\ORM\Mapping\User:
|
||||
type: entity
|
||||
table: cms_users
|
||||
options:
|
||||
foo: bar
|
||||
baz:
|
||||
key: val
|
||||
namedQueries:
|
||||
all: SELECT u FROM __CLASS__ u
|
||||
id:
|
||||
|
@ -18,6 +22,10 @@ Doctrine\Tests\ORM\Mapping\User:
|
|||
length: 50
|
||||
nullable: true
|
||||
unique: true
|
||||
options:
|
||||
foo: bar
|
||||
baz:
|
||||
key: val
|
||||
email:
|
||||
type: string
|
||||
column: user_email
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
namespace Doctrine\Tests\ORM\Persisters;
|
||||
|
||||
use Doctrine\DBAL\Types\Type as DBALType;
|
||||
use Doctrine\ORM\Persisters\BasicEntityPersister;
|
||||
|
|
|
@ -52,7 +52,7 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
|||
public function testReferenceProxyDelegatesLoadingToThePersister()
|
||||
{
|
||||
$identifier = array('id' => 42);
|
||||
$proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy';
|
||||
$proxyClass = 'Proxies\__CG__\Doctrine\Tests\Models\ECommerce\ECommerceFeature';
|
||||
$persister = $this->_getMockPersister();
|
||||
$this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister);
|
||||
|
||||
|
@ -69,7 +69,7 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
|||
public function testReferenceProxyExecutesLoadingOnlyOnce()
|
||||
{
|
||||
$identifier = array('id' => 42);
|
||||
$proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy';
|
||||
$proxyClass = 'Proxies\__CG__\Doctrine\Tests\Models\ECommerce\ECommerceFeature';
|
||||
$persister = $this->_getMockPersister();
|
||||
$this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister);
|
||||
$proxy = $this->_proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $identifier);
|
||||
|
@ -108,7 +108,7 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
|||
|
||||
public function testCreatesAssociationProxyAsSubclassOfTheOriginalOne()
|
||||
{
|
||||
$proxyClass = 'Proxies\DoctrineTestsModelsECommerceECommerceFeatureProxy';
|
||||
$proxyClass = 'Proxies\__CG__\Doctrine\Tests\Models\ECommerce\ECommerceFeature';
|
||||
$this->assertTrue(is_subclass_of($proxyClass, 'Doctrine\Tests\Models\ECommerce\ECommerceFeature'));
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
|||
require_once dirname(__FILE__)."/fixtures/NonNamespacedProxies.php";
|
||||
|
||||
$className = "\DoctrineOrmTestEntity";
|
||||
$proxyName = "DoctrineOrmTestEntityProxy";
|
||||
$proxyName = "DoctrineOrmTestEntity";
|
||||
$classMetadata = new \Doctrine\ORM\Mapping\ClassMetadata($className);
|
||||
$classMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
$classMetadata->mapField(array('fieldName' => 'id', 'type' => 'integer'));
|
||||
|
@ -133,16 +133,16 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
|||
|
||||
$this->_proxyFactory->generateProxyClasses(array($classMetadata));
|
||||
|
||||
$classCode = file_get_contents(dirname(__FILE__)."/generated/".$proxyName.".php");
|
||||
$classCode = file_get_contents(dirname(__FILE__)."/generated/__CG__".$proxyName.".php");
|
||||
|
||||
$this->assertNotContains("class DoctrineOrmTestEntityProxy extends \\\\DoctrineOrmTestEntity", $classCode);
|
||||
$this->assertContains("class DoctrineOrmTestEntityProxy extends \\DoctrineOrmTestEntity", $classCode);
|
||||
$this->assertNotContains("class DoctrineOrmTestEntity extends \\\\DoctrineOrmTestEntity", $classCode);
|
||||
$this->assertContains("class DoctrineOrmTestEntity extends \\DoctrineOrmTestEntity", $classCode);
|
||||
}
|
||||
|
||||
public function testClassWithSleepProxyGeneration()
|
||||
{
|
||||
$className = "\Doctrine\Tests\ORM\Proxy\SleepClass";
|
||||
$proxyName = "DoctrineTestsORMProxySleepClassProxy";
|
||||
$proxyName = "DoctrineTestsORMProxySleepClass";
|
||||
$classMetadata = new \Doctrine\ORM\Mapping\ClassMetadata($className);
|
||||
$classMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
|
||||
$classMetadata->mapField(array('fieldName' => 'id', 'type' => 'integer'));
|
||||
|
@ -150,7 +150,7 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
|||
|
||||
$this->_proxyFactory->generateProxyClasses(array($classMetadata));
|
||||
|
||||
$classCode = file_get_contents(dirname(__FILE__)."/generated/".$proxyName.".php");
|
||||
$classCode = file_get_contents(dirname(__FILE__)."/generated/__CG__".$proxyName.".php");
|
||||
|
||||
$this->assertEquals(1, substr_count($classCode, 'function __sleep'));
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Doctrine\Tests\ORM\Query;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
|
||||
class QueryTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
|
@ -90,4 +90,39 @@ class QueryTest extends \Doctrine\Tests\OrmTestCase
|
|||
$this->assertEquals('baz', $q->getHint('bar'));
|
||||
$this->assertEquals(array('foo' => 'bar', 'bar' => 'baz'), $q->getHints());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1588
|
||||
*/
|
||||
public function testQueryDefaultResultCache()
|
||||
{
|
||||
$this->_em->getConfiguration()->setResultCacheImpl(new ArrayCache());
|
||||
$q = $this->_em->createQuery("select a from Doctrine\Tests\Models\CMS\CmsArticle a");
|
||||
$q->useResultCache(true);
|
||||
$this->assertSame($this->_em->getConfiguration()->getResultCacheImpl(), $q->getQueryCacheProfile()->getResultCacheDriver());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Doctrine\ORM\Query\QueryException
|
||||
**/
|
||||
public function testIterateWithNoDistinctAndWrongSelectClause()
|
||||
{
|
||||
$q = $this->_em->createQuery("select u, a from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a");
|
||||
$q->iterate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Doctrine\ORM\Query\QueryException
|
||||
**/
|
||||
public function testIterateWithNoDistinctAndWithValidSelectClause()
|
||||
{
|
||||
$q = $this->_em->createQuery("select u from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a");
|
||||
$q->iterate();
|
||||
}
|
||||
|
||||
public function testIterateWithDistinct()
|
||||
{
|
||||
$q = $this->_em->createQuery("SELECT DISTINCT u from Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a");
|
||||
$q->iterate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1074,7 +1074,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT t, s, l FROM Doctrine\Tests\Models\DDC117\DDC117Link l INNER JOIN l.target t INNER JOIN l.source s",
|
||||
"SELECT d0_.article_id AS article_id0, d0_.title AS title1, d1_.article_id AS article_id2, d1_.title AS title3 FROM DDC117Link d2_ INNER JOIN DDC117Article d0_ ON d2_.target_id = d0_.article_id INNER JOIN DDC117Article d1_ ON d2_.source_id = d1_.article_id"
|
||||
"SELECT d0_.article_id AS article_id0, d0_.title AS title1, d1_.article_id AS article_id2, d1_.title AS title3, d2_.source_id AS source_id4, d2_.target_id AS target_id5 FROM DDC117Link d2_ INNER JOIN DDC117Article d0_ ON d2_.target_id = d0_.article_id INNER JOIN DDC117Article d1_ ON d2_.source_id = d1_.article_id"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1535,6 +1535,17 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||
'SELECT c0_.id AS id0, -(c0_.customInteger) AS customInteger1 FROM customtype_parents c0_'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1529
|
||||
*/
|
||||
public function testMultipleFromAndInheritanceCondition()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT fix, flex FROM Doctrine\Tests\Models\Company\CompanyFixContract fix, Doctrine\Tests\Models\Company\CompanyFlexContract flex',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c1_.id AS id3, c1_.completed AS completed4, c1_.hoursWorked AS hoursWorked5, c1_.pricePerHour AS pricePerHour6, c1_.maxPrice AS maxPrice7, c0_.discr AS discr8, c1_.discr AS discr9 FROM company_contracts c0_, company_contracts c1_ WHERE (c0_.discr IN ('fix') AND c1_.discr IN ('flexible', 'flexultra'))"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -732,4 +732,17 @@ class QueryBuilderTest extends \Doctrine\Tests\OrmTestCase
|
|||
|
||||
$this->assertEquals('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u', $qb->getDQL());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1619
|
||||
*/
|
||||
public function testAddDistinct()
|
||||
{
|
||||
$qb = $this->_em->createQueryBuilder()
|
||||
->select('u')
|
||||
->distinct()
|
||||
->from('Doctrine\Tests\Models\CMS\CmsUser', 'u');
|
||||
|
||||
$this->assertEquals('SELECT DISTINCT u FROM Doctrine\Tests\Models\CMS\CmsUser u', $qb->getDQL());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
|||
$this->_generator->setGenerateStubMethods(true);
|
||||
$this->_generator->setRegenerateEntityIfExists(false);
|
||||
$this->_generator->setUpdateEntityIfExists(true);
|
||||
$this->_generator->setFieldVisibility(EntityGenerator::FIELD_VISIBLE_PROTECTED);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
|
@ -47,6 +48,8 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
|||
$metadata->customRepositoryClassName = $this->_namespace . '\EntityGeneratorBookRepository';
|
||||
|
||||
$metadata->table['name'] = 'book';
|
||||
$metadata->table['uniqueConstraints']['name_uniq'] = array('columns' => array('name'));
|
||||
$metadata->table['indexes']['status_idx'] = array('columns' => array('status'));
|
||||
$metadata->mapField(array('fieldName' => 'name', 'type' => 'string'));
|
||||
$metadata->mapField(array('fieldName' => 'status', 'type' => 'string', 'default' => 'published'));
|
||||
$metadata->mapField(array('fieldName' => 'id', 'type' => 'integer', 'id' => true));
|
||||
|
@ -133,7 +136,7 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
|||
$this->assertTrue($reflClass->hasProperty('id'), "Regenerating keeps property 'id'.");
|
||||
|
||||
$this->assertTrue($reflClass->hasProperty('test'), "Check for property test failed.");
|
||||
$this->assertTrue($reflClass->getProperty('test')->isPrivate(), "Check for private property test failed.");
|
||||
$this->assertTrue($reflClass->getProperty('test')->isProtected(), "Check for protected property test failed.");
|
||||
$this->assertTrue($reflClass->hasMethod('getTest'), "Check for method 'getTest' failed.");
|
||||
$this->assertTrue($reflClass->getMethod('getTest')->isPublic(), "Check for public visibility of method 'getTest' failed.");
|
||||
$this->assertTrue($reflClass->hasMethod('setTest'), "Check for method 'getTest' failed.");
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Tools\Pagination\CountWalker;
|
||||
|
||||
/**
|
||||
* @group DDC-1613
|
||||
*/
|
||||
class CountWalkerTest extends PaginationTestCase
|
||||
{
|
||||
public function testCountQuery()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost p JOIN p.category c JOIN p.author a');
|
||||
$query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker'));
|
||||
$query->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
$query->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT count(DISTINCT b0_.id) AS sclr0 FROM BlogPost b0_ INNER JOIN Category c1_ ON b0_.category_id = c1_.id INNER JOIN Author a2_ ON b0_.author_id = a2_.id", $query->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCountQuery_MixedResultsWithName()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a');
|
||||
$query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker'));
|
||||
$query->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
$query->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT count(DISTINCT a0_.id) AS sclr0 FROM Author a0_", $query->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCountQuery_KeepsGroupBy()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT b FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost b GROUP BY b.id');
|
||||
$query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker'));
|
||||
$query->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
$query->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT count(DISTINCT b0_.id) AS sclr0 FROM BlogPost b0_ GROUP BY b0_.id", $query->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCountQuery_RemovesOrderBy()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost p JOIN p.category c JOIN p.author a ORDER BY a.name');
|
||||
$query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker'));
|
||||
$query->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
$query->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT count(DISTINCT b0_.id) AS sclr0 FROM BlogPost b0_ INNER JOIN Category c1_ ON b0_.category_id = c1_.id INNER JOIN Author a2_ ON b0_.author_id = a2_.id", $query->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCountQuery_RemovesLimits()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost p JOIN p.category c JOIN p.author a');
|
||||
$query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker'));
|
||||
$query->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
$query->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT count(DISTINCT b0_.id) AS sclr0 FROM BlogPost b0_ INNER JOIN Category c1_ ON b0_.category_id = c1_.id INNER JOIN Author a2_ ON b0_.author_id = a2_.id", $query->getSql()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
|
||||
/**
|
||||
* @group DDC-1613
|
||||
*/
|
||||
class LimitSubqueryWalkerTest extends PaginationTestCase
|
||||
{
|
||||
public function testLimitSubquery()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a');
|
||||
$limitQuery = clone $query;
|
||||
$limitQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker'));
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT DISTINCT m0_.id AS id0 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id", $limitQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCountQuery_MixedResultsWithName()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a');
|
||||
$limitQuery = clone $query;
|
||||
$limitQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker'));
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT DISTINCT a0_.id AS id0, sum(a0_.name) AS sclr1 FROM Author a0_", $limitQuery->getSql()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
142
tests/Doctrine/Tests/ORM/Tools/Pagination/PaginationTestCase.php
Normal file
142
tests/Doctrine/Tests/ORM/Tools/Pagination/PaginationTestCase.php
Normal file
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\Tests\OrmTestCase;
|
||||
|
||||
abstract class PaginationTestCase extends OrmTestCase
|
||||
{
|
||||
public $entityManager;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->entityManager = $this->_getTestEntityManager();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class MyBlogPost
|
||||
{
|
||||
|
||||
/** @Id @column(type="integer") @generatedValue */
|
||||
public $id;
|
||||
/**
|
||||
* @ManyToOne(targetEntity="Author")
|
||||
*/
|
||||
public $author;
|
||||
/**
|
||||
* @ManyToOne(targetEntity="Category")
|
||||
*/
|
||||
public $category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class MyAuthor
|
||||
{
|
||||
|
||||
/** @Id @column(type="integer") @generatedValue */
|
||||
public $id;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class MyCategory
|
||||
{
|
||||
|
||||
/** @id @column(type="integer") @generatedValue */
|
||||
public $id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class BlogPost
|
||||
{
|
||||
|
||||
/** @Id @column(type="integer") @generatedValue */
|
||||
public $id;
|
||||
/**
|
||||
* @ManyToOne(targetEntity="Author")
|
||||
*/
|
||||
public $author;
|
||||
/**
|
||||
* @ManyToOne(targetEntity="Category")
|
||||
*/
|
||||
public $category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class Author
|
||||
{
|
||||
|
||||
/** @Id @column(type="integer") @generatedValue */
|
||||
public $id;
|
||||
/** @Column(type="string") */
|
||||
public $name;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class Person
|
||||
{
|
||||
|
||||
/** @Id @column(type="integer") @generatedValue */
|
||||
public $id;
|
||||
/** @Column(type="string") */
|
||||
public $name;
|
||||
/** @Column(type="string") */
|
||||
public $biography;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class Category
|
||||
{
|
||||
|
||||
/** @id @column(type="integer") @generatedValue */
|
||||
public $id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** @Entity @Table(name="groups") */
|
||||
class Group
|
||||
{
|
||||
|
||||
/** @Id @column(type="integer") @generatedValue */
|
||||
public $id;
|
||||
/** @ManyToMany(targetEntity="User", mappedBy="groups") */
|
||||
public $users;
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class User
|
||||
{
|
||||
|
||||
/** @Id @column(type="integer") @generatedValue */
|
||||
public $id;
|
||||
/**
|
||||
* @ManyToMany(targetEntity="Group", inversedBy="users")
|
||||
* @JoinTable(
|
||||
* name="user_group",
|
||||
* joinColumns = {@JoinColumn(name="user_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns = {@JoinColumn(name="group_id", referencedColumnName="id")}
|
||||
* )
|
||||
*/
|
||||
public $groups;
|
||||
}
|
125
tests/Doctrine/Tests/ORM/Tools/Pagination/WhereInWalkerTest.php
Normal file
125
tests/Doctrine/Tests/ORM/Tools/Pagination/WhereInWalkerTest.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools\Pagination;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Tools\Pagination\WhereInWalker;
|
||||
|
||||
/**
|
||||
* @group DDC-1613
|
||||
*/
|
||||
class WhereInWalkerTest extends PaginationTestCase
|
||||
{
|
||||
public function testWhereInQuery_NoWhere()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g'
|
||||
);
|
||||
$whereInQuery = clone $query;
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCountQuery_MixedResultsWithName()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT a, sum(a.name) as foo FROM Doctrine\Tests\ORM\Tools\Pagination\Author a'
|
||||
);
|
||||
$whereInQuery = clone $query;
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT a0_.id AS id0, a0_.name AS name1, sum(a0_.name) AS sclr2 FROM Author a0_ WHERE a0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testWhereInQuery_SingleWhere()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE 1 = 1'
|
||||
);
|
||||
$whereInQuery = clone $query;
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE 1 = 1 AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testWhereInQuery_MultipleWhereWithAnd()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE 1 = 1 AND 2 = 2'
|
||||
);
|
||||
$whereInQuery = clone $query;
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE 1 = 1 AND 2 = 2 AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testWhereInQuery_MultipleWhereWithOr()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE 1 = 1 OR 2 = 2'
|
||||
);
|
||||
$whereInQuery = clone $query;
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE (1 = 1 OR 2 = 2) AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testWhereInQuery_MultipleWhereWithMixed_1()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE (1 = 1 OR 2 = 2) AND 3 = 3'
|
||||
);
|
||||
$whereInQuery = clone $query;
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE (1 = 1 OR 2 = 2) AND 3 = 3 AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testWhereInQuery_MultipleWhereWithMixed_2()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE 1 = 1 AND 2 = 2 OR 3 = 3'
|
||||
);
|
||||
$whereInQuery = clone $query;
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE (1 = 1 AND 2 = 2 OR 3 = 3) AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testWhereInQuery_WhereNot()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT u, g FROM Doctrine\Tests\ORM\Tools\Pagination\User u JOIN u.groups g WHERE NOT 1 = 2'
|
||||
);
|
||||
$whereInQuery = clone $query;
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT u0_.id AS id0, g1_.id AS id1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE (NOT 1 = 2) AND u0_.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,23 @@ class SchemaToolTest extends \Doctrine\Tests\OrmTestCase
|
|||
$this->assertTrue($schema->getTable('cms_users')->columnsAreIndexed(array('username')), "username column should be indexed.");
|
||||
}
|
||||
|
||||
public function testAnnotationOptionsAttribute()
|
||||
{
|
||||
$em = $this->_getTestEntityManager();
|
||||
$schemaTool = new SchemaTool($em);
|
||||
|
||||
$classes = array(
|
||||
$em->getClassMetadata(__NAMESPACE__ . '\\TestEntityWithAnnotationOptionsAttribute'),
|
||||
);
|
||||
|
||||
$schema = $schemaTool->getSchemaFromMetadata($classes);
|
||||
|
||||
$expected = array('foo' => 'bar', 'baz' => array('key' => 'val'));
|
||||
|
||||
$this->assertEquals($expected, $schema->getTable('TestEntityWithAnnotationOptionsAttribute')->getOptions(), "options annotation are passed to the tables optionss");
|
||||
$this->assertEquals($expected, $schema->getTable('TestEntityWithAnnotationOptionsAttribute')->getColumn('test')->getCustomSchemaOptions(), "options annotation are passed to the columns customSchemaOptions");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-200
|
||||
*/
|
||||
|
@ -86,6 +103,21 @@ class SchemaToolTest extends \Doctrine\Tests\OrmTestCase
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(options={"foo": "bar", "baz": {"key": "val"}})
|
||||
*/
|
||||
class TestEntityWithAnnotationOptionsAttribute
|
||||
{
|
||||
/** @Id @Column */
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @Column(type="string", options={"foo": "bar", "baz": {"key": "val"}})
|
||||
*/
|
||||
private $test;
|
||||
}
|
||||
|
||||
class GenerateSchemaEventListener
|
||||
{
|
||||
public $tableCalls = 0;
|
||||
|
|
|
@ -103,12 +103,39 @@ class SchemaValidatorTest extends \Doctrine\Tests\OrmTestCase
|
|||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
"The referenced column name 'id' does not have a corresponding field with this column name on the class 'Doctrine\Tests\ORM\Tools\InvalidEntity1'.",
|
||||
"The join columns of the association 'assoc' have to match to ALL identifier columns of the source entity 'Doctrine\Tests\ORM\Tools\InvalidEntity2', however 'key3, key4' are missing."
|
||||
"The referenced column name 'id' has to be a primary key column on the target entity class 'Doctrine\Tests\ORM\Tools\InvalidEntity1'.",
|
||||
"The join columns of the association 'assoc' have to match to ALL identifier columns of the target entity 'Doctrine\Tests\ORM\Tools\InvalidEntity2', however 'key1, key2' are missing."
|
||||
),
|
||||
$ce
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1587
|
||||
*/
|
||||
public function testValidOneToOneAsIdentifierSchema()
|
||||
{
|
||||
$class1 = $this->em->getClassMetadata(__NAMESPACE__ . '\DDC1587ValidEntity2');
|
||||
$class2 = $this->em->getClassMetadata(__NAMESPACE__ . '\DDC1587ValidEntity1');
|
||||
|
||||
$ce = $this->validator->validateClass($class1);
|
||||
|
||||
$this->assertEquals(array(), $ce);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1649
|
||||
*/
|
||||
public function testInvalidTripleAssociationAsKeyMapping()
|
||||
{
|
||||
$classThree = $this->em->getClassMetadata(__NAMESPACE__ . '\DDC1649Three');
|
||||
$ce = $this->validator->validateClass($classThree);
|
||||
|
||||
$this->assertEquals(Array(
|
||||
"Cannot map association 'Doctrine\Tests\ORM\Tools\DDC1649Three#two as identifier, because the target entity 'Doctrine\Tests\ORM\Tools\DDC1649Two' also maps an association as identifier.",
|
||||
"The referenced column name 'id' has to be a primary key column on the target entity class 'Doctrine\Tests\ORM\Tools\DDC1649Two'."
|
||||
), $ce);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,3 +181,87 @@ class InvalidEntity2
|
|||
*/
|
||||
protected $assoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity(repositoryClass="Entity\Repository\Agent")
|
||||
* @Table(name="agent")
|
||||
*/
|
||||
class DDC1587ValidEntity1
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @Id @GeneratedValue
|
||||
* @Column(name="pk", type="integer")
|
||||
*/
|
||||
private $pk;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @Column(name="name", type="string", length=32)
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var Identifier
|
||||
*
|
||||
* @OneToOne(targetEntity="DDC1587ValidEntity2", cascade={"all"}, mappedBy="agent")
|
||||
* @JoinColumn(name="pk", referencedColumnName="pk_agent")
|
||||
*/
|
||||
private $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table
|
||||
*/
|
||||
class DDC1587ValidEntity2
|
||||
{
|
||||
/**
|
||||
* @var DDC1587ValidEntity1
|
||||
*
|
||||
* @Id
|
||||
* @OneToOne(targetEntity="DDC1587ValidEntity1", inversedBy="identifier")
|
||||
* @JoinColumn(name="pk_agent", referencedColumnName="pk", nullable=false)
|
||||
*/
|
||||
private $agent;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @Column(name="num", type="string", length=16, nullable=true)
|
||||
*/
|
||||
private $num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1649One
|
||||
{
|
||||
/**
|
||||
* @Id @Column @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1649Two
|
||||
{
|
||||
/** @Id @ManyToOne(targetEntity="DDC1649One")@JoinColumn(name="id", referencedColumnName="id") */
|
||||
public $one;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1649Three
|
||||
{
|
||||
/** @Id @ManyToOne(targetEntity="DDC1649Two") @JoinColumn(name="id",
|
||||
* referencedColumnName="id") */
|
||||
private $two;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,21 @@ class SetupTest extends \Doctrine\Tests\OrmTestCase
|
|||
$this->originalIncludePath = get_include_path();
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
if ( ! $this->originalIncludePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_include_path($this->originalIncludePath);
|
||||
$loaders = spl_autoload_functions();
|
||||
for ($i = 0; $i < count($loaders); $i++) {
|
||||
if ($i > $this->originalAutoloaderCount+1) {
|
||||
spl_autoload_unregister($loaders[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testGitAutoload()
|
||||
{
|
||||
Setup::registerAutoloadGit(__DIR__ . "/../../../../../");
|
||||
|
@ -92,15 +107,4 @@ class SetupTest extends \Doctrine\Tests\OrmTestCase
|
|||
$this->assertSame($cache, $config->getMetadataCacheImpl());
|
||||
$this->assertSame($cache, $config->getQueryCacheImpl());
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
set_include_path($this->originalIncludePath);
|
||||
$loaders = spl_autoload_functions();
|
||||
for ($i = 0; $i < count($loaders); $i++) {
|
||||
if ($i > $this->originalAutoloaderCount+1) {
|
||||
spl_autoload_unregister($loaders[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,12 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
|
|||
/** Whether the database schema has already been created. */
|
||||
protected static $_tablesCreated = array();
|
||||
|
||||
/**
|
||||
* Array of entity class name to their tables that were created.
|
||||
* @var array
|
||||
*/
|
||||
protected static $_entityTablesCreated = array();
|
||||
|
||||
/** List of model sets and their classes. */
|
||||
protected static $_modelSets = array(
|
||||
'cms' => array(
|
||||
|
@ -235,6 +241,25 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
|
|||
$this->_em->clear();
|
||||
}
|
||||
|
||||
protected function setUpEntitySchema(array $classNames)
|
||||
{
|
||||
if ($this->_em === null) {
|
||||
throw new \RuntimeException("EntityManager not set, you have to call parent::setUp() before invoking this method.");
|
||||
}
|
||||
|
||||
$classes = array();
|
||||
foreach ($classNames as $className) {
|
||||
if ( ! isset(static::$_entityTablesCreated[$className])) {
|
||||
static::$_entityTablesCreated[$className] = true;
|
||||
$classes[] = $this->_em->getClassMetadata($className);
|
||||
}
|
||||
}
|
||||
|
||||
if ($classes) {
|
||||
$this->_schemaTool->createSchema($classes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a connection to the test database, if there is none yet, and
|
||||
* creates the necessary tables.
|
||||
|
|
Loading…
Add table
Reference in a new issue