1
0
mirror of synced 2025-01-29 19:41:45 +03:00

Merge doctrine/master

This commit is contained in:
Vitali Yakavenka 2012-01-06 22:06:59 +03:00
commit 59e9d55077
61 changed files with 2002 additions and 531 deletions

View File

@ -1,7 +1,8 @@
# Doctrine 2 ORM
Master: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=master)](http://travis-ci.org/doctrine/doctrine2)
2.1.x: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.1.x)](http://travis-ci.org/doctrine/doctrine2)
2.2: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.2)](http://travis-ci.org/doctrine/doctrine2)
2.1: [![Build Status](https://secure.travis-ci.org/doctrine/doctrine2.png?branch=2.1.x)](http://travis-ci.org/doctrine/doctrine2)
Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.2+ that provides transparent persistence
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features

View File

@ -2,8 +2,8 @@
project.name=DoctrineORM
# Dependency minimum versions
dependencies.common=2.1.0
dependencies.dbal=2.1.0
dependencies.common=2.2.0beta1
dependencies.dbal=2.2.0beta1
dependencies.sfconsole=2.0.0
# Version class and file

View File

@ -94,8 +94,8 @@
<pear minimum_version="1.6.0" recommended_version="1.6.1" />
<package name="DoctrineCommon" channel="pear.doctrine-project.org" minimum_version="${dependencies.common}" />
<package name="DoctrineDBAL" channel="pear.doctrine-project.org" minimum_version="${dependencies.dbal}" />
<package name="Console" channel="pear.symfony.org" minimum_version="2.0.0" />
<package name="Yaml" channel="pear.symfony.org" minimum_version="2.0.0" />
<package name="Console" channel="pear.symfony.com" minimum_version="2.0.0" />
<package name="Yaml" channel="pear.symfony.com" minimum_version="2.0.0" />
</dependencies>
<dirroles key="bin">script</dirroles>
<ignore>Doctrine/Common/</ignore>

View File

@ -605,7 +605,7 @@ abstract class AbstractQuery
/**
* Set the result cache id to use to store the result set cache entry.
* If this is not explicitely set by the developer then a hash is automatically
* If this is not explicitly set by the developer then a hash is automatically
* generated for you.
*
* @param string $id

View File

@ -24,7 +24,9 @@ use Doctrine\Common\Cache\Cache,
Doctrine\Common\Annotations\AnnotationRegistry,
Doctrine\Common\Annotations\AnnotationReader,
Doctrine\ORM\Mapping\Driver\Driver,
Doctrine\ORM\Mapping\Driver\AnnotationDriver;
Doctrine\ORM\Mapping\Driver\AnnotationDriver,
Doctrine\ORM\Mapping\NamingStrategy,
Doctrine\ORM\Mapping\DefaultNamingStrategy;
/**
* Configuration container for all configuration options of Doctrine.
@ -548,4 +550,29 @@ class Configuration extends \Doctrine\DBAL\Configuration
return isset($this->_attributes['defaultRepositoryClassName']) ?
$this->_attributes['defaultRepositoryClassName'] : 'Doctrine\ORM\EntityRepository';
}
/**
* Set naming strategy.
*
* @since 2.3
* @param NamingStrategy $namingStrategy
*/
public function setNamingStrategy(NamingStrategy $namingStrategy)
{
$this->_attributes['namingStrategy'] = $namingStrategy;
}
/**
* Get naming strategy..
*
* @since 2.3
* @return NamingStrategy
*/
public function getNamingStrategy()
{
if (!isset($this->_attributes['namingStrategy'])) {
$this->_attributes['namingStrategy'] = new DefaultNamingStrategy();
}
return $this->_attributes['namingStrategy'];
}
}

View File

@ -488,7 +488,7 @@ class EntityManager implements ObjectManager
public function persist($entity)
{
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()' , $entity);
}
$this->errorIfClosed();
@ -507,7 +507,7 @@ class EntityManager implements ObjectManager
public function remove($entity)
{
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()' , $entity);
}
$this->errorIfClosed();
@ -524,7 +524,7 @@ class EntityManager implements ObjectManager
public function refresh($entity)
{
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()' , $entity);
}
$this->errorIfClosed();
@ -544,7 +544,7 @@ class EntityManager implements ObjectManager
public function detach($entity)
{
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()' , $entity);
}
$this->unitOfWork->detach($entity);
@ -561,7 +561,7 @@ class EntityManager implements ObjectManager
public function merge($entity)
{
if ( ! is_object($entity)) {
throw new \InvalidArgumentException(gettype($entity));
throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()' , $entity);
}
$this->errorIfClosed();

View File

@ -36,22 +36,22 @@ use PDO,
*/
abstract class AbstractHydrator
{
/** @var ResultSetMapping The ResultSetMapping. */
/** @var \Doctrine\ORM\Query\ResultSetMapping The ResultSetMapping. */
protected $_rsm;
/** @var EntityManager The EntityManager instance. */
protected $_em;
/** @var AbstractPlatform The dbms Platform instance */
/** @var \Doctrine\DBAL\Platforms\AbstractPlatform The dbms Platform instance */
protected $_platform;
/** @var UnitOfWork The UnitOfWork of the associated EntityManager. */
/** @var \Doctrine\ORM\UnitOfWork The UnitOfWork of the associated EntityManager. */
protected $_uow;
/** @var array The cache used during row-by-row hydration. */
protected $_cache = array();
/** @var Statement The statement that provides the data to hydrate. */
/** @var \Doctrine\DBAL\Driver\Statement The statement that provides the data to hydrate. */
protected $_stmt;
/** @var array The query hints. */
@ -93,6 +93,7 @@ abstract class AbstractHydrator
*
* @param object $stmt
* @param object $resultSetMapping
* @param array $hints
* @return mixed
*/
public function hydrateAll($stmt, $resultSetMapping, array $hints = array())

View File

@ -208,8 +208,8 @@ class ObjectHydrator extends AbstractHydrator
/**
* Gets an entity instance.
*
* @param $data The instance data.
* @param $dqlAlias The DQL alias of the entity's class.
* @param array $data The instance data.
* @param string $dqlAlias The DQL alias of the entity's class.
* @return object The entity.
*/
private function _getEntity(array $data, $dqlAlias)

View File

@ -20,7 +20,6 @@
namespace Doctrine\ORM\Mapping;
use ReflectionClass, ReflectionProperty;
use Doctrine\Common\Persistence\Mapping\ClassMetadata AS IClassMetadata;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
@ -40,325 +39,6 @@ use Doctrine\Common\Persistence\Mapping\ClassMetadata AS IClassMetadata;
* @author Jonathan H. Wage <jonwage@gmail.com>
* @since 2.0
*/
class ClassMetadata extends ClassMetadataInfo implements IClassMetadata
class ClassMetadata extends ClassMetadataInfo
{
/**
* The ReflectionProperty instances of the mapped class.
*
* @var array
*/
public $reflFields = array();
/**
* The prototype from which new instances of the mapped class are created.
*
* @var object
*/
private $_prototype;
/**
* 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.
*/
public function __construct($entityName)
{
$this->reflClass = new ReflectionClass($entityName);
$this->namespace = $this->reflClass->getNamespaceName();
$this->table['name'] = $this->reflClass->getShortName();
parent::__construct($this->reflClass->getName()); // do not use $entityName, possible case-problems
}
/**
* Gets the ReflectionPropertys of the mapped class.
*
* @return array An array of ReflectionProperty instances.
*/
public function getReflectionProperties()
{
return $this->reflFields;
}
/**
* Gets a ReflectionProperty for a specific field of the mapped class.
*
* @param string $name
* @return ReflectionProperty
*/
public function getReflectionProperty($name)
{
return $this->reflFields[$name];
}
/**
* Gets the ReflectionProperty for the single identifier field.
*
* @return ReflectionProperty
* @throws BadMethodCallException If the class has a composite identifier.
*/
public function getSingleIdReflectionProperty()
{
if ($this->isIdentifierComposite) {
throw new \BadMethodCallException("Class " . $this->name . " has a composite identifier.");
}
return $this->reflFields[$this->identifier[0]];
}
/**
* Validates & completes the given field mapping.
*
* @param array $mapping The field mapping to validated & complete.
* @return array The validated and completed field mapping.
*
* @throws MappingException
*/
protected function _validateAndCompleteFieldMapping(array &$mapping)
{
parent::_validateAndCompleteFieldMapping($mapping);
// Store ReflectionProperty of mapped field
$refProp = $this->reflClass->getProperty($mapping['fieldName']);
$refProp->setAccessible(true);
$this->reflFields[$mapping['fieldName']] = $refProp;
}
/**
* Extracts the identifier values of an entity of this class.
*
* For composite identifiers, the identifier values are returned as an array
* with the same order as the field order in {@link identifier}.
*
* @param object $entity
* @return array
*/
public function getIdentifierValues($entity)
{
if ($this->isIdentifierComposite) {
$id = array();
foreach ($this->identifier as $idField) {
$value = $this->reflFields[$idField]->getValue($entity);
if ($value !== null) {
$id[$idField] = $value;
}
}
return $id;
}
$value = $this->reflFields[$this->identifier[0]]->getValue($entity);
if ($value !== null) {
return array($this->identifier[0] => $value);
}
return array();
}
/**
* Populates the entity identifier of an entity.
*
* @param object $entity
* @param mixed $id
* @todo Rename to assignIdentifier()
*/
public function setIdentifierValues($entity, array $id)
{
foreach ($id as $idField => $idValue) {
$this->reflFields[$idField]->setValue($entity, $idValue);
}
}
/**
* Sets the specified field to the specified value on the given entity.
*
* @param object $entity
* @param string $field
* @param mixed $value
*/
public function setFieldValue($entity, $field, $value)
{
$this->reflFields[$field]->setValue($entity, $value);
}
/**
* Gets the specified field's value off the given entity.
*
* @param object $entity
* @param string $field
*/
public function getFieldValue($entity, $field)
{
return $this->reflFields[$field]->getValue($entity);
}
/**
* Stores the association mapping.
*
* @param AssociationMapping $assocMapping
*/
protected function _storeAssociationMapping(array $assocMapping)
{
parent::_storeAssociationMapping($assocMapping);
// Store ReflectionProperty of mapped field
$sourceFieldName = $assocMapping['fieldName'];
$refProp = $this->reflClass->getProperty($sourceFieldName);
$refProp->setAccessible(true);
$this->reflFields[$sourceFieldName] = $refProp;
}
/**
* Creates a string representation of this instance.
*
* @return string The string representation of this instance.
* @todo Construct meaningful string representation.
*/
public function __toString()
{
return __CLASS__ . '@' . spl_object_hash($this);
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
* Parts that are also NOT serialized because they can not be properly unserialized:
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
// This metadata is always serialized/cached.
$serialized = array(
'associationMappings',
'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName']
'fieldMappings',
'fieldNames',
'identifier',
'isIdentifierComposite', // TODO: REMOVE
'name',
'namespace', // TODO: REMOVE
'table',
'rootEntityName',
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
);
// The rest of the metadata is only serialized if necessary.
if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) {
$serialized[] = 'changeTrackingPolicy';
}
if ($this->customRepositoryClassName) {
$serialized[] = 'customRepositoryClassName';
}
if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) {
$serialized[] = 'inheritanceType';
$serialized[] = 'discriminatorColumn';
$serialized[] = 'discriminatorValue';
$serialized[] = 'discriminatorMap';
$serialized[] = 'parentClasses';
$serialized[] = 'subClasses';
}
if ($this->generatorType != self::GENERATOR_TYPE_NONE) {
$serialized[] = 'generatorType';
if ($this->generatorType == self::GENERATOR_TYPE_SEQUENCE) {
$serialized[] = 'sequenceGeneratorDefinition';
}
}
if ($this->isMappedSuperclass) {
$serialized[] = 'isMappedSuperclass';
}
if ($this->containsForeignIdentifier) {
$serialized[] = 'containsForeignIdentifier';
}
if ($this->isVersioned) {
$serialized[] = 'isVersioned';
$serialized[] = 'versionField';
}
if ($this->lifecycleCallbacks) {
$serialized[] = 'lifecycleCallbacks';
}
if ($this->namedQueries) {
$serialized[] = 'namedQueries';
}
if ($this->isReadOnly) {
$serialized[] = 'isReadOnly';
}
return $serialized;
}
/**
* Restores some state that can not be serialized/unserialized.
*
* @return void
*/
public function __wakeup()
{
// Restore ReflectionClass and properties
$this->reflClass = new ReflectionClass($this->name);
foreach ($this->fieldMappings as $field => $mapping) {
$reflField = isset($mapping['declared'])
? new ReflectionProperty($mapping['declared'], $field)
: $this->reflClass->getProperty($field);
$reflField->setAccessible(true);
$this->reflFields[$field] = $reflField;
}
foreach ($this->associationMappings as $field => $mapping) {
$reflField = isset($mapping['declared'])
? new ReflectionProperty($mapping['declared'], $field)
: $this->reflClass->getProperty($field);
$reflField->setAccessible(true);
$this->reflFields[$field] = $reflField;
}
}
/**
* Creates a new instance of the mapped class, without invoking the constructor.
*
* @return object
*/
public function newInstance()
{
if ($this->_prototype === null) {
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
}
return clone $this->_prototype;
}
/**
* @param string $callback
* @param string $event
*/
public function addLifecycleCallback($callback, $event)
{
if ( !$this->reflClass->hasMethod($callback) ||
($this->reflClass->getMethod($callback)->getModifiers() & \ReflectionMethod::IS_PUBLIC) == 0) {
throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callback);
}
return parent::addLifecycleCallback($callback, $event);
}
}

View File

@ -24,6 +24,8 @@ use ReflectionException,
Doctrine\ORM\EntityManager,
Doctrine\DBAL\Platforms,
Doctrine\ORM\Events,
Doctrine\Common\Persistence\Mapping\RuntimeReflectionService,
Doctrine\Common\Persistence\Mapping\ReflectionService,
Doctrine\Common\Persistence\Mapping\ClassMetadataFactory as ClassMetadataFactoryInterface;
/**
@ -74,6 +76,11 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
*/
private $initialized = false;
/**
* @var ReflectionService
*/
private $reflectionService;
/**
* @param EntityManager $$em
*/
@ -165,6 +172,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
if ($this->cacheDriver) {
if (($cached = $this->cacheDriver->fetch("$realClassName\$CLASSMETADATA")) !== false) {
$this->wakeupReflection($cached, $this->getReflectionService());
$this->loadedMetadata[$realClassName] = $cached;
} else {
foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
@ -220,7 +228,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
{
// Collect parent classes, ignoring transient (not-mapped) classes.
$parentClasses = array();
foreach (array_reverse(class_parents($name)) as $parentClass) {
foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) {
if ( ! $this->driver->isTransient($parentClass)) {
$parentClasses[] = $parentClass;
}
@ -261,6 +269,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
}
$class = $this->newClassMetadataInstance($className);
$this->initializeReflection($class, $this->getReflectionService());
if ($parent) {
$class->setInheritanceType($parent->inheritanceType);
@ -282,6 +291,7 @@ 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);
}
@ -349,11 +359,15 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
*/
protected function validateRuntimeMetadata($class, $parent)
{
// Verify & complete identifier mapping
if ( ! $class->identifier && ! $class->isMappedSuperclass) {
throw MappingException::identifierRequired($class->name);
if ( ! $class->reflClass ) {
// only validate if there is a reflection class instance
return;
}
$class->validateIdentifier();
$class->validateAssocations();
$class->validateLifecycleCallbacks($this->getReflectionService());
// verify inheritance
if (!$class->isMappedSuperclass && !$class->isInheritanceTypeNone()) {
if (!$parent) {
@ -371,10 +385,6 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
// second condition is necessary for mapped superclasses in the middle of an inheritance hierachy
throw MappingException::noInheritanceOnMappedSuperClass($class->name);
}
if ($class->usesIdGenerator() && $class->isIdentifierComposite) {
throw MappingException::compositeKeyAssignedIdGeneratorRequired($class->name);
}
}
/**
@ -385,7 +395,7 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
*/
protected function newClassMetadataInstance($className)
{
return new ClassMetadata($className);
return new ClassMetadata($className, $this->em->getConfiguration()->getNamingStrategy());
}
/**
@ -546,4 +556,51 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
return $this->driver->isTransient($class);
}
/**
* Get reflectionService.
*
* @return \Doctrine\Common\Persistence\Mapping\ReflectionService
*/
public function getReflectionService()
{
if ($this->reflectionService === null) {
$this->reflectionService = new RuntimeReflectionService();
}
return $this->reflectionService;
}
/**
* Set reflectionService.
*
* @param reflectionService the value to set.
*/
public function setReflectionService(ReflectionService $reflectionService)
{
$this->reflectionService = $reflectionService;
}
/**
* Wakeup reflection after ClassMetadata gets unserialized from cache.
*
* @param ClassMetadataInfo $class
* @param ReflectionService $reflService
* @return void
*/
protected function wakeupReflection(ClassMetadataInfo $class, ReflectionService $reflService)
{
$class->wakeupReflection($reflService);
}
/**
* Initialize Reflection after ClassMetadata was constructed.
*
* @param ClassMetadataInfo $class
* @param ReflectionService $reflService
* @return void
*/
protected function initializeReflection(ClassMetadataInfo $class, ReflectionService $reflService)
{
$class->initializeReflection($reflService);
}
}

View File

@ -21,6 +21,7 @@ namespace Doctrine\ORM\Mapping;
use Doctrine\DBAL\Types\Type;
use ReflectionClass;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
@ -40,7 +41,7 @@ use ReflectionClass;
* @author Jonathan H. Wage <jonwage@gmail.com>
* @since 2.0
*/
class ClassMetadataInfo
class ClassMetadataInfo implements ClassMetadata
{
/* The inheritance mapping types */
/**
@ -443,7 +444,7 @@ class ClassMetadataInfo
/**
* READ-ONLY: The ID generator used for generating IDs for this class.
*
* @var AbstractIdGenerator
* @var \Doctrine\ORM\Id\AbstractIdGenerator
* @todo Remove!
*/
public $idGenerator;
@ -515,16 +516,341 @@ class ClassMetadataInfo
*/
public $isReadOnly = false;
/**
* NamingStrategy determining the default column and table names
*
* @var \Doctrine\ORM\NamingStrategy
*/
protected $namingStrategy;
/**
* The ReflectionProperty instances of the mapped class.
*
* @var array
*/
public $reflFields = array();
/**
* The prototype from which new instances of the mapped class are created.
*
* @var object
*/
private $_prototype;
/**
* 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 NamingStrategy $namingStrategy
*/
public function __construct($entityName, NamingStrategy $namingStrategy = null)
{
$this->name = $entityName;
$this->rootEntityName = $entityName;
$this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy();
}
/**
* Gets the ReflectionPropertys of the mapped class.
*
* @return array An array of ReflectionProperty instances.
*/
public function getReflectionProperties()
{
return $this->reflFields;
}
/**
* Gets a ReflectionProperty for a specific field of the mapped class.
*
* @param string $name
* @return ReflectionProperty
*/
public function getReflectionProperty($name)
{
return $this->reflFields[$name];
}
/**
* Gets the ReflectionProperty for the single identifier field.
*
* @return ReflectionProperty
* @throws BadMethodCallException If the class has a composite identifier.
*/
public function getSingleIdReflectionProperty()
{
if ($this->isIdentifierComposite) {
throw new \BadMethodCallException("Class " . $this->name . " has a composite identifier.");
}
return $this->reflFields[$this->identifier[0]];
}
/**
* Extracts the identifier values of an entity of this class.
*
* For composite identifiers, the identifier values are returned as an array
* with the same order as the field order in {@link identifier}.
*
* @param object $entity
* @return array
*/
public function getIdentifierValues($entity)
{
if ($this->isIdentifierComposite) {
$id = array();
foreach ($this->identifier as $idField) {
$value = $this->reflFields[$idField]->getValue($entity);
if ($value !== null) {
$id[$idField] = $value;
}
}
return $id;
}
$value = $this->reflFields[$this->identifier[0]]->getValue($entity);
if ($value !== null) {
return array($this->identifier[0] => $value);
}
return array();
}
/**
* Populates the entity identifier of an entity.
*
* @param object $entity
* @param mixed $id
* @todo Rename to assignIdentifier()
*/
public function setIdentifierValues($entity, array $id)
{
foreach ($id as $idField => $idValue) {
$this->reflFields[$idField]->setValue($entity, $idValue);
}
}
/**
* Sets the specified field to the specified value on the given entity.
*
* @param object $entity
* @param string $field
* @param mixed $value
*/
public function setFieldValue($entity, $field, $value)
{
$this->reflFields[$field]->setValue($entity, $value);
}
/**
* Gets the specified field's value off the given entity.
*
* @param object $entity
* @param string $field
*/
public function getFieldValue($entity, $field)
{
return $this->reflFields[$field]->getValue($entity);
}
/**
* Creates a string representation of this instance.
*
* @return string The string representation of this instance.
* @todo Construct meaningful string representation.
*/
public function __toString()
{
return __CLASS__ . '@' . spl_object_hash($this);
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
* Parts that are also NOT serialized because they can not be properly unserialized:
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
// This metadata is always serialized/cached.
$serialized = array(
'associationMappings',
'columnNames', //TODO: Not really needed. Can use fieldMappings[$fieldName]['columnName']
'fieldMappings',
'fieldNames',
'identifier',
'isIdentifierComposite', // TODO: REMOVE
'name',
'namespace', // TODO: REMOVE
'table',
'rootEntityName',
'idGenerator', //TODO: Does not really need to be serialized. Could be moved to runtime.
);
// The rest of the metadata is only serialized if necessary.
if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) {
$serialized[] = 'changeTrackingPolicy';
}
if ($this->customRepositoryClassName) {
$serialized[] = 'customRepositoryClassName';
}
if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE) {
$serialized[] = 'inheritanceType';
$serialized[] = 'discriminatorColumn';
$serialized[] = 'discriminatorValue';
$serialized[] = 'discriminatorMap';
$serialized[] = 'parentClasses';
$serialized[] = 'subClasses';
}
if ($this->generatorType != self::GENERATOR_TYPE_NONE) {
$serialized[] = 'generatorType';
if ($this->generatorType == self::GENERATOR_TYPE_SEQUENCE) {
$serialized[] = 'sequenceGeneratorDefinition';
}
}
if ($this->isMappedSuperclass) {
$serialized[] = 'isMappedSuperclass';
}
if ($this->containsForeignIdentifier) {
$serialized[] = 'containsForeignIdentifier';
}
if ($this->isVersioned) {
$serialized[] = 'isVersioned';
$serialized[] = 'versionField';
}
if ($this->lifecycleCallbacks) {
$serialized[] = 'lifecycleCallbacks';
}
if ($this->namedQueries) {
$serialized[] = 'namedQueries';
}
if ($this->isReadOnly) {
$serialized[] = 'isReadOnly';
}
return $serialized;
}
/**
* Creates a new instance of the mapped class, without invoking the constructor.
*
* @return object
*/
public function newInstance()
{
if ($this->_prototype === null) {
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
}
return clone $this->_prototype;
}
/**
* Restores some state that can not be serialized/unserialized.
*
* @param ReflectionService $reflService
* @return void
*/
public function wakeupReflection($reflService)
{
// Restore ReflectionClass and properties
$this->reflClass = $reflService->getClass($this->name);
foreach ($this->fieldMappings as $field => $mapping) {
$this->reflFields[$field] = isset($mapping['declared'])
? $reflService->getAccessibleProperty($mapping['declared'], $field)
: $reflService->getAccessibleProperty($this->name, $field);
}
foreach ($this->associationMappings as $field => $mapping) {
$this->reflFields[$field] = isset($mapping['declared'])
? $reflService->getAccessibleProperty($mapping['declared'], $field)
: $reflService->getAccessibleProperty($this->name, $field);
}
}
/**
* 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.
*/
public function __construct($entityName)
public function initializeReflection($reflService)
{
$this->name = $entityName;
$this->rootEntityName = $entityName;
$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();
}
}
/**
* Validate Identifier
*
* @return void
*/
public function validateIdentifier()
{
// Verify & complete identifier mapping
if ( ! $this->identifier && ! $this->isMappedSuperclass) {
throw MappingException::identifierRequired($this->name);
}
if ($this->usesIdGenerator() && $this->isIdentifierComposite) {
throw MappingException::compositeKeyAssignedIdGeneratorRequired($this->name);
}
}
/**
* Validate association targets actually exist.
*
* @return void
*/
public function validateAssocations()
{
foreach ($this->associationMappings as $field => $mapping) {
if ( ! \Doctrine\Common\ClassLoader::classExists($mapping['targetEntity']) ) {
throw MappingException::invalidTargetEntityClass($mapping['targetEntity'], $this->name, $mapping['fieldName']);
}
}
}
/**
* Validate lifecycle callbacks
*
* @param ReflectionService $reflService
* @return void
*/
public function validateLifecycleCallbacks($reflService)
{
foreach ($this->lifecycleCallbacks as $event => $callbacks) {
foreach ($callbacks as $callbackFuncName) {
if ( ! $reflService->hasPublicMethod($this->name, $callbackFuncName)) {
throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callbackFuncName);
}
}
}
}
/**
@ -534,9 +860,6 @@ class ClassMetadataInfo
*/
public function getReflectionClass()
{
if ( ! $this->reflClass) {
$this->reflClass = new ReflectionClass($this->name);
}
return $this->reflClass;
}
@ -738,7 +1061,7 @@ class ClassMetadataInfo
// Complete fieldName and columnName mapping
if ( ! isset($mapping['columnName'])) {
$mapping['columnName'] = $mapping['fieldName'];
$mapping['columnName'] = $this->namingStrategy->propertyToColumnName($mapping['fieldName']);
} else {
if ($mapping['columnName'][0] == '`') {
$mapping['columnName'] = trim($mapping['columnName'], '`');
@ -907,8 +1230,8 @@ class ClassMetadataInfo
if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) {
// Apply default join column
$mapping['joinColumns'] = array(array(
'name' => $mapping['fieldName'] . '_id',
'referencedColumnName' => 'id'
'name' => $this->namingStrategy->joinColumnName($mapping['fieldName']),
'referencedColumnName' => $this->namingStrategy->referenceColumnName()
));
}
@ -922,10 +1245,10 @@ class ClassMetadataInfo
}
}
if (empty($joinColumn['name'])) {
$joinColumn['name'] = $mapping['fieldName'] . '_id';
$joinColumn['name'] = $this->namingStrategy->joinColumnName($mapping['fieldName']);
}
if (empty($joinColumn['referencedColumnName'])) {
$joinColumn['referencedColumnName'] = 'id';
$joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
}
$mapping['sourceToTargetKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
$mapping['joinColumnFieldNames'][$joinColumn['name']] = isset($joinColumn['fieldName'])
@ -986,40 +1309,29 @@ class ClassMetadataInfo
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
if ($mapping['isOwningSide']) {
if (strpos($mapping['sourceEntity'], '\\') !== false) {
$sourceShortName = strtolower(substr($mapping['sourceEntity'], strrpos($mapping['sourceEntity'], '\\') + 1));
} else {
$sourceShortName = strtolower($mapping['sourceEntity']);
}
if (strpos($mapping['targetEntity'], '\\') !== false) {
$targetShortName = strtolower(substr($mapping['targetEntity'], strrpos($mapping['targetEntity'], '\\') + 1));
} else {
$targetShortName = strtolower($mapping['targetEntity']);
}
// owning side MUST have a join table
if ( ! isset($mapping['joinTable']['name'])) {
$mapping['joinTable']['name'] = $sourceShortName .'_' . $targetShortName;
$mapping['joinTable']['name'] = $this->namingStrategy->joinTableName($mapping['sourceEntity'], $mapping['targetEntity'], $mapping['fieldName']);
}
if ( ! isset($mapping['joinTable']['joinColumns'])) {
$mapping['joinTable']['joinColumns'] = array(array(
'name' => $sourceShortName . '_id',
'referencedColumnName' => 'id',
'name' => $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity']),
'referencedColumnName' => $this->namingStrategy->referenceColumnName(),
'onDelete' => 'CASCADE'));
}
if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
$mapping['joinTable']['inverseJoinColumns'] = array(array(
'name' => $targetShortName . '_id',
'referencedColumnName' => 'id',
'name' => $this->namingStrategy->joinKeyColumnName($mapping['targetEntity']),
'referencedColumnName' => $this->namingStrategy->referenceColumnName(),
'onDelete' => 'CASCADE'));
}
foreach ($mapping['joinTable']['joinColumns'] as &$joinColumn) {
if (empty($joinColumn['name'])) {
$joinColumn['name'] = $sourceShortName . '_id';
$joinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['sourceEntity'], $joinColumn['referencedColumnName']);
}
if (empty($joinColumn['referencedColumnName'])) {
$joinColumn['referencedColumnName'] = 'id';
$joinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
}
if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) == 'cascade') {
$mapping['isOnDeleteCascade'] = true;
@ -1030,10 +1342,10 @@ class ClassMetadataInfo
foreach ($mapping['joinTable']['inverseJoinColumns'] as &$inverseJoinColumn) {
if (empty($inverseJoinColumn['name'])) {
$inverseJoinColumn['name'] = $targetShortName . '_id';
$inverseJoinColumn['name'] = $this->namingStrategy->joinKeyColumnName($mapping['targetEntity'], $inverseJoinColumn['referencedColumnName']);
}
if (empty($inverseJoinColumn['referencedColumnName'])) {
$inverseJoinColumn['referencedColumnName'] = 'id';
$inverseJoinColumn['referencedColumnName'] = $this->namingStrategy->referenceColumnName();
}
if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) == 'cascade') {
$mapping['isOnDeleteCascade'] = true;
@ -1399,7 +1711,7 @@ class ClassMetadataInfo
{
if (isset($table['name'])) {
if ($table['name'][0] == '`') {
$this->table['name'] = trim($table['name'], '`');
$this->table['name'] = str_replace("`", "", $table['name']);
$this->table['quoted'] = true;
} else {
$this->table['name'] = $table['name'];

View File

@ -0,0 +1,86 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* The default NamingStrategy
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.3
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class DefaultNamingStrategy implements NamingStrategy
{
/**
* {@inheritdoc}
*/
public function classToTableName($className)
{
if (strpos($className, '\\') !== false) {
return substr($className, strrpos($className, '\\') + 1);
}
return $className;
}
/**
* {@inheritdoc}
*/
public function propertyToColumnName($propertyName)
{
return $propertyName;
}
/**
* {@inheritdoc}
*/
public function referenceColumnName()
{
return 'id';
}
/**
* {@inheritdoc}
*/
public function joinColumnName($propertyName)
{
return $propertyName . '_' . $this->referenceColumnName();
}
/**
* {@inheritdoc}
*/
public function joinTableName($sourceEntity, $targetEntity, $propertyName = null)
{
return strtolower($this->classToTableName($sourceEntity) . '_' .
$this->classToTableName($targetEntity));
}
/**
* {@inheritdoc}
*/
public function joinKeyColumnName($entityName, $referencedColumnName = null)
{
return strtolower($this->classToTableName($entityName) . '_' .
($referencedColumnName ?: $this->referenceColumnName()));
}
}

View File

@ -61,7 +61,6 @@ class SimplifiedYamlDriver extends YamlDriver
$this->_prefixes[$path] = $prefix;
}
public function getNamespacePrefixes()
{
return $this->_prefixes;

View File

@ -324,4 +324,9 @@ class MappingException extends \Doctrine\ORM\ORMException
{
return new self("Entity '". $className . "' has a composite identifier but uses an ID generator other than manually assigning (Identity, Sequence). This is not supported.");
}
public static function invalidTargetEntityClass($targetEntity, $sourceEntity, $associationName)
{
return new self("The target-entity " . $targetEntity . " cannot be found in '" . $sourceEntity."#".$associationName."'.");
}
}

View File

@ -0,0 +1,82 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* A set of rules for determining the physical column and table names
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.3
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
interface NamingStrategy
{
/**
* Return a table name for an entity class
*
* @param string $className The fully-qualified class name
* @return string A table name
*/
function classToTableName($className);
/**
* Return a column name for a property
*
* @param string $propertyName A property
* @return string A column name
*/
function propertyToColumnName($propertyName);
/**
* Return the default reference column name
*
* @return string A column name
*/
function referenceColumnName();
/**
* Return a join column name for a property
*
* @param string $propertyName A property
* @return string A join column name
*/
function joinColumnName($propertyName);
/**
* Return a join table name
*
* @param string $sourceEntity The source entity
* @param string $targetEntity The target entity
* @param string $propertyName A property
* @return string A join table name
*/
function joinTableName($sourceEntity, $targetEntity, $propertyName = null);
/**
* Return the foreign key column name for the given parameters
*
* @param string $entityName A entity
* @param string $referencedColumnName A property
* @return string A join column name
*/
function joinKeyColumnName($entityName, $referencedColumnName = null);
}

View File

@ -0,0 +1,135 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* Naming strategy implementing the underscore naming convention.
* Converts 'MyEntity' to 'my_entity' or 'MY_ENTITY'.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.3
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
*/
class UnderscoreNamingStrategy implements NamingStrategy
{
/**
* @var integer
*/
private $case;
/**
* Underscore naming strategy construct
*
* @param integer $case CASE_LOWER | CASE_UPPER
*/
public function __construct($case = CASE_LOWER)
{
$this->case = $case;
}
/**
* @return integer
*/
public function getCase()
{
return $this->case;
}
/**
* Sets string case CASE_LOWER | CASE_UPPER
* Alphabetic characters converted to lowercase or uppercase
*
* @param integer $case
*/
public function setCase($case)
{
$this->case = $case;
}
/**
* {@inheritdoc}
*/
public function classToTableName($className)
{
if (strpos($className, '\\') !== false) {
$className = substr($className, strrpos($className, '\\') + 1);
}
return $this->underscore($className);
}
/**
* {@inheritdoc}
*/
public function propertyToColumnName($propertyName)
{
return $this->underscore($propertyName);
}
/**
* {@inheritdoc}
*/
public function referenceColumnName()
{
return $this->case === CASE_UPPER ? 'ID' : 'id';
}
/**
* {@inheritdoc}
*/
public function joinColumnName($propertyName)
{
return $this->underscore($propertyName) . '_' . $this->referenceColumnName();
}
/**
* {@inheritdoc}
*/
public function joinTableName($sourceEntity, $targetEntity, $propertyName = null)
{
return $this->classToTableName($sourceEntity) . '_' . $this->classToTableName($targetEntity);
}
/**
* {@inheritdoc}
*/
public function joinKeyColumnName($entityName, $referencedColumnName = null)
{
return $this->classToTableName($entityName) . '_' .
($referencedColumnName ?: $this->referenceColumnName());
}
/**
* @param string $string
* @return string
*/
private function underscore($string)
{
$string = preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $string);
if ($this->case === CASE_UPPER) {
return strtoupper($string);
}
return strtolower($string);
}
}

View File

@ -0,0 +1,113 @@
<?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;
/**
* Contains exception messages for all invalid lifecycle state exceptions inside UnitOfWork
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class ORMInvalidArgumentException extends \InvalidArgumentException
{
static public function scheduleInsertForManagedEntity($entity)
{
return new self("A managed+dirty entity " . self::objToStr($entity) . " can not be scheduled for insertion.");
}
static public function scheduleInsertForRemovedEntity($entity)
{
return new self("Removed entity " . self::objToStr($entity) . " can not be scheduled for insertion.");
}
static public function scheduleInsertTwice($entity)
{
return new self("Entity " . self::objToStr($entity) . " can not be scheduled for insertion twice.");
}
static public function entityWithoutIdentity($className, $entity)
{
throw new self(
"The given entity of type '" . $className . "' (".self::objToStr($entity).") has no identity/no " .
"id values set. It cannot be added to the identity map."
);
}
static public function readOnlyRequiresManagedEntity($entity)
{
return new self("Only managed entities can be marked or checked as read only. But " . self::objToStr($entity) . " is not");
}
static public function newEntityFoundThroughRelationship(array $assoc, $entry)
{
return new self("A new entity was found through the relationship '"
. $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' that was not"
. " configured to cascade persist operations for entity: " . self::objToStr($entry) . "."
. " To solve this issue: Either explicitly call EntityManager#persist()"
. " on this unknown entity or configure cascade persist "
. " this association in the mapping for example @ManyToOne(..,cascade={\"persist\"}). "
. " If you cannot find out which entity causes the problem"
. " implement '" . $assoc['targetEntity'] . "#__toString()' to get a clue.");
}
static public function detachedEntityFoundThroughRelationship(array $assoc, $entry)
{
throw new self("A detached entity of type " . $assoc['targetEntity'] . " (" . self::objToStr($entry) . ") "
. " was found through the relationship '" . $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' "
. "during cascading a persist operation.");
}
static public function entityNotManaged($entity)
{
throw new self("Entity " . self::objToStr($entity) . " is not managed. An entity is managed if its fetched " .
"from the database or registered as new through EntityManager#persist");
}
static public function entityHasNoIdentity($entity, $operation)
{
throw new self("Entity has no identity, therefore " . $operation ." cannot be performed. " . self::objToStr($entity));
}
static public function entityIsRemoved($entity, $operation)
{
throw new self("Entity is removed, therefore " . $operation ." cannot be performed. " . self::objToStr($entity));
}
static public function detachedEntityCannot($entity, $operation)
{
throw new self("A detached entity was found during " . $operation . " " . self::objToStr($entity));
}
public static function invalidObject($context, $given, $parameterIndex = 1)
{
return new self($context .' expects parameter ' . $parameterIndex .
' to be an entity object, '. gettype($given) . ' given.');
}
/**
* Helper method to show an object as string.
*
* @param object $obj
* @return string
*/
private static function objToStr($obj)
{
return method_exists($obj, '__toString') ? (string)$obj : get_class($obj).'@'.spl_object_hash($obj);
}
}

View File

@ -192,7 +192,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
*/
public function count(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
$mapping = $filterMapping = $coll->getMapping();
$class = $this->_em->getClassMetadata($mapping['sourceEntity']);
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
@ -218,7 +218,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
: $id[$class->fieldNames[$joinColumns[$joinTableColumn]]];
}
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
if ($filterSql) {
$whereClauses[] = $filterSql;
}
@ -295,7 +295,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
private function getJoinTableRestrictions(PersistentCollection $coll, $element, $addFilters)
{
$uow = $this->_em->getUnitOfWork();
$mapping = $coll->getMapping();
$mapping = $filterMapping = $coll->getMapping();
if ( ! $mapping['isOwningSide']) {
$sourceClass = $this->_em->getClassMetadata($mapping['targetEntity']);
@ -332,7 +332,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
}
if ($addFilters) {
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
if ($filterSql) {
$quotedJoinTable .= ' t ' . $joinTargetEntitySQL;
$whereClauses[] = $filterSql;
@ -351,13 +351,21 @@ class ManyToManyPersister extends AbstractCollectionPersister
* have to join in the actual entities table leading to additional
* JOIN.
*
* @param array $targetEntity Array containing mapping information.
* @param array $mapping Array containing mapping information.
*
* @return string The SQL query part to add to a query.
*/
public function getFilterSql($mapping)
{
$targetClass = $this->_em->getClassMetadata($mapping['targetEntity']);
if ($mapping['isOwningSide']) {
$joinColumns = $mapping['relationToTargetKeyColumns'];
} else {
$mapping = $targetClass->associationMappings[$mapping['mappedBy']];
$joinColumns = $mapping['relationToSourceKeyColumns'];
}
$targetClass = $this->_em->getClassMetadata($targetClass->rootEntityName);
// A join is needed if there is filtering on the target entity
@ -368,7 +376,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
. ' ON';
$joinTargetEntitySQLClauses = array();
foreach ($mapping['relationToTargetKeyColumns'] as $joinTableColumn => $targetTableColumn) {
foreach ($joinColumns as $joinTableColumn => $targetTableColumn) {
$joinTargetEntitySQLClauses[] = ' t.' . $joinTableColumn . ' = ' . 'te.' . $targetTableColumn;
}

View File

@ -119,8 +119,9 @@ class OneToManyPersister extends AbstractCollectionPersister
: $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]];
}
$filterTargetClass = $this->_em->getClassMetadata($targetClass->rootEntityName);
foreach ($this->_em->getFilters()->getEnabledFilters() as $filter) {
if ($filterExpr = $filter->addFilterConstraint($targetClass, 't')) {
if ($filterExpr = $filter->addFilterConstraint($filterTargetClass, 't')) {
$whereClauses[] = '(' . $filterExpr . ')';
}
}

View File

@ -75,7 +75,7 @@ class Expr
* Creates an ASCending order expression.
*
* @param $sort
* @return OrderBy
* @return Expr\OrderBy
*/
public function asc($expr)
{
@ -86,7 +86,7 @@ class Expr
* Creates a DESCending order expression.
*
* @param $sort
* @return OrderBy
* @return Expr\OrderBy
*/
public function desc($expr)
{

View File

@ -1981,9 +1981,10 @@ class Parser
}
/**
* SimpleSelectExpression ::=
* StateFieldPathExpression | IdentificationVariable |
* ((AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable])
* SimpleSelectExpression ::= (
* StateFieldPathExpression | IdentificationVariable | FunctionDeclaration |
* AggregateExpression | "(" Subselect ")" | ScalarExpression
* ) [["AS"] AliasResultVariable]
*
* @return \Doctrine\ORM\Query\AST\SimpleSelectExpression
*/
@ -2004,6 +2005,18 @@ class Parser
return new AST\SimpleSelectExpression($expression);
case ($this->_isFunction()):
// SUM(u.id) + COUNT(u.id)
if ($this->_isMathOperator($this->_peekBeyondClosingParenthesis())) {
return new AST\SimpleSelectExpression($this->ScalarExpression());
}
// COUNT(u.id)
if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
return new AST\SimpleSelectExpression($this->AggregateExpression());
}
// IDENTITY(u)
return new AST\SimpleSelectExpression($this->FunctionDeclaration());
default:
// Do nothing
}
@ -2151,7 +2164,8 @@ class Parser
$peek = $this->_peekBeyondClosingParenthesis();
if (in_array($peek['value'], array("=", "<", "<=", "<>", ">", ">=", "!=")) ||
in_array($peek['type'], array(Lexer::T_NOT, Lexer::T_BETWEEN, Lexer::T_LIKE, Lexer::T_IN, Lexer::T_IS, Lexer::T_EXISTS))) {
in_array($peek['type'], array(Lexer::T_NOT, Lexer::T_BETWEEN, Lexer::T_LIKE, Lexer::T_IN, Lexer::T_IS, Lexer::T_EXISTS)) ||
$this->_isMathOperator($peek)) {
$condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
return $condPrimary;
@ -2812,7 +2826,7 @@ class Parser
}
/**
* LikeExpression ::= StringExpression ["NOT"] "LIKE" (string | input_parameter) ["ESCAPE" char]
* LikeExpression ::= StringExpression ["NOT"] "LIKE" StringPrimary ["ESCAPE" char]
*
* @return \Doctrine\ORM\Query\AST\LikeExpression
*/
@ -2832,8 +2846,7 @@ class Parser
$this->match(Lexer::T_INPUT_PARAMETER);
$stringPattern = new AST\InputParameter($this->_lexer->token['value']);
} else {
$this->match(Lexer::T_STRING);
$stringPattern = $this->_lexer->token['value'];
$stringPattern = $this->StringPrimary();
}
$escapeChar = null;

View File

@ -1947,6 +1947,10 @@ class SqlWalker implements TreeWalker
$dqlParamKey = $inputParam->name;
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
$sql .= '?';
} elseif ($likeExpr->stringPattern instanceof AST\Functions\FunctionNode ) {
$sql .= $this->walkFunction($likeExpr->stringPattern);
} elseif ($likeExpr->stringPattern instanceof AST\PathExpression) {
$sql .= $this->walkPathExpression($likeExpr->stringPattern);
} else {
$sql .= $this->_conn->quote($likeExpr->stringPattern);
}

View File

@ -119,7 +119,7 @@ class QueryBuilder
* For more complex expression construction, consider storing the expression
* builder object in a local variable.
*
* @return Expr
* @return Query\Expr
*/
public function expr()
{

View File

@ -38,36 +38,8 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo;
*/
class DisconnectedClassMetadataFactory extends ClassMetadataFactory
{
/**
* @override
*/
protected function newClassMetadataInstance($className)
public function getReflectionService()
{
$metadata = new ClassMetadataInfo($className);
if (strpos($className, "\\") !== false) {
$metadata->namespace = strrev(substr( strrev($className), strpos(strrev($className), "\\")+1 ));
} else {
$metadata->namespace = "";
}
return $metadata;
return new \Doctrine\Common\Persistence\Mapping\StaticReflectionService;
}
/**
* Validate runtime metadata is correctly defined.
*
* @param ClassMetadata $class
* @param ClassMetadata $parent
*/
protected function validateRuntimeMetadata($class, $parent)
{
// validate nothing
}
/**
* @override
*/
protected function getParentClasses($name)
{
return array();
}
}
}

View File

@ -111,16 +111,18 @@ abstract class AbstractExporter
}
foreach ($this->_metadata as $metadata) {
$output = $this->exportClassMetadata($metadata);
$path = $this->_generateOutputPath($metadata);
$dir = dirname($path);
if ( ! is_dir($dir)) {
mkdir($dir, 0777, true);
//In case output is returned, write it to a file, skip otherwise
if($output = $this->exportClassMetadata($metadata)){
$path = $this->_generateOutputPath($metadata);
$dir = dirname($path);
if ( ! is_dir($dir)) {
mkdir($dir, 0777, true);
}
if (file_exists($path) && !$this->_overwriteExistingFiles) {
throw ExportException::attemptOverwriteExistingFile($path);
}
file_put_contents($path, $output);
}
if (file_exists($path) && !$this->_overwriteExistingFiles) {
throw ExportException::attemptOverwriteExistingFile($path);
}
file_put_contents($path, $output);
}
}

View File

@ -710,14 +710,7 @@ class UnitOfWork implements PropertyChangedListener
switch ($state) {
case self::STATE_NEW:
if ( ! $assoc['isCascadePersist']) {
$message = "A new entity was found through the relationship '%s#%s' that was not configured " .
' to cascade persist operations for entity: %s. Explicitly persist the new entity or ' .
'configure cascading persist operations on the relationship. If you cannot find out ' .
'which entity causes the problem, implement %s#__toString() to get a clue.';
throw new InvalidArgumentException(sprintf(
$message, $assoc['sourceEntity'], $assoc['fieldName'], self::objToStr($entry), $assoc['targetEntity']
));
throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry);
}
$this->persistNew($targetClass, $entry);
@ -735,9 +728,7 @@ class UnitOfWork implements PropertyChangedListener
case self::STATE_DETACHED:
// Can actually not happen right now as we assume STATE_NEW,
// so the exception will be raised from the DBAL layer (constraint violation).
$message = 'A detached entity was found through a relationship during cascading a persist operation.';
throw new InvalidArgumentException($message);
throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry);
break;
default:
@ -797,7 +788,7 @@ class UnitOfWork implements PropertyChangedListener
$oid = spl_object_hash($entity);
if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) {
throw new InvalidArgumentException('Entity must be managed.');
throw ORMInvalidArgumentException::entityNotManaged($entity);
}
// skip if change tracking is "NOTIFY"
@ -1077,11 +1068,14 @@ class UnitOfWork implements PropertyChangedListener
}
if (isset($this->entityDeletions[$oid])) {
throw new InvalidArgumentException("Removed entity can not be scheduled for insertion.");
throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity);
}
if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid])) {
throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity);
}
if (isset($this->entityInsertions[$oid])) {
throw new InvalidArgumentException("Entity can not be scheduled for insertion twice.");
throw ORMInvalidArgumentException::scheduleInsertTwice($entity);
}
$this->entityInsertions[$oid] = $entity;
@ -1112,11 +1106,11 @@ class UnitOfWork implements PropertyChangedListener
$oid = spl_object_hash($entity);
if ( ! isset($this->entityIdentifiers[$oid])) {
throw new InvalidArgumentException("Entity has no identity.");
throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "scheduling for update");
}
if (isset($this->entityDeletions[$oid])) {
throw new InvalidArgumentException("Entity is removed.");
throw ORMInvalidArgumentException::entityIsRemoved($entity, "schedule for update");
}
if ( ! isset($this->entityUpdates[$oid]) && ! isset($this->entityInsertions[$oid])) {
@ -1256,7 +1250,7 @@ class UnitOfWork implements PropertyChangedListener
$idHash = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]);
if ($idHash === '') {
throw new InvalidArgumentException('The given entity has no identity.');
throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity);
}
$className = $classMetadata->rootEntityName;
@ -1366,7 +1360,7 @@ class UnitOfWork implements PropertyChangedListener
$idHash = implode(' ', $this->entityIdentifiers[$oid]);
if ($idHash === '') {
throw new InvalidArgumentException('The given entity has no identity.');
throw ORMInvalidArgumentException::entityHasNoIdentity($entity, "remove from identity map");
}
$className = $classMetadata->rootEntityName;
@ -1513,10 +1507,10 @@ class UnitOfWork implements PropertyChangedListener
case self::STATE_DETACHED:
// Can actually not happen right now since we assume STATE_NEW.
throw new InvalidArgumentException('Detached entity passed to persist().');
throw ORMInvalidArgumentException::detachedEntityCannot($entity, "persisted");
default:
throw new UnexpectedValueException(sprintf('Unexpected entity state: %s', $entityState));
throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
}
$this->cascadePersist($entity, $visited);
@ -1580,10 +1574,9 @@ class UnitOfWork implements PropertyChangedListener
break;
case self::STATE_DETACHED:
throw new InvalidArgumentException('A detached entity can not be removed.');
throw ORMInvalidArgumentException::detachedEntityCannot($entity, "removed");
default:
throw new UnexpectedValueException(sprintf('Unexpected entity state: %s', $entityState));
throw new UnexpectedValueException("Unexpected entity state: $entityState." . self::objToStr($entity));
}
}
@ -1665,8 +1658,7 @@ class UnitOfWork implements PropertyChangedListener
if ($managedCopy) {
// We have the entity in-memory already, just make sure its not removed.
if ($this->getEntityState($managedCopy) == self::STATE_REMOVED) {
throw new InvalidArgumentException('Removed entity detected during merge.'
. ' Can not merge with a removed entity.');
throw ORMInvalidArgumentException::entityIsRemoved($managedCopy, "merge");
}
} else {
// We need to fetch the managed copy in order to merge.
@ -1883,7 +1875,7 @@ class UnitOfWork implements PropertyChangedListener
$class = $this->em->getClassMetadata(get_class($entity));
if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
throw new InvalidArgumentException("Entity is not MANAGED.");
throw ORMInvalidArgumentException::entityNotManaged($entity);
}
$this->getEntityPersister($class->name)->refresh(
@ -2107,7 +2099,7 @@ class UnitOfWork implements PropertyChangedListener
public function lock($entity, $lockMode, $lockVersion = null)
{
if ($this->getEntityState($entity, self::STATE_DETACHED) != self::STATE_MANAGED) {
throw new InvalidArgumentException("Entity is not MANAGED.");
throw ORMInvalidArgumentException::entityNotManaged($entity);
}
$entityName = get_class($entity);
@ -2881,7 +2873,7 @@ class UnitOfWork implements PropertyChangedListener
public function markReadOnly($object)
{
if ( ! is_object($object) || ! $this->isInIdentityMap($object)) {
throw new InvalidArgumentException("Managed entity required");
throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
}
$this->readOnlyObjects[spl_object_hash($object)] = true;
@ -2897,7 +2889,7 @@ class UnitOfWork implements PropertyChangedListener
public function isReadOnly($object)
{
if ( ! is_object($object) ) {
throw new InvalidArgumentException("Managed entity required");
throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
}
return isset($this->readOnlyObjects[spl_object_hash($object)]);

View File

@ -36,7 +36,7 @@ class Version
/**
* Current Doctrine Version
*/
const VERSION = '2.2.0-DEV';
const VERSION = '2.3.0-DEV';
/**
* Compares a Doctrine version with the current one.

@ -1 +1 @@
Subproject commit 5c43f26f82bde0234c0645e349fb12a48bd39c7f
Subproject commit 5812b7acdc962196140e6b9f7a4758fb6d6f4933

@ -1 +1 @@
Subproject commit ef7382756672d99c92b746aea56f10295edfc96b
Subproject commit cc04744bcf5a4743c46fae0487ac7a093a722856

@ -1 +1 @@
Subproject commit 4410e4cec20b0f1f209578320e5b7d111e90c2a0
Subproject commit 29b714b7fe72641d749ae90324a5759853fe09b0

View File

@ -14,4 +14,4 @@ class CompanyAuction extends CompanyEvent {
public function getData() {
return $this->data;
}
}
}

View File

@ -21,7 +21,7 @@ abstract class CompanyContract
private $id;
/**
* @ManyToOne(targetEntity="CompanyEmployee")
* @ManyToOne(targetEntity="CompanyEmployee", inversedBy="soldContracts")
*/
private $salesPerson;
@ -32,7 +32,7 @@ abstract class CompanyContract
private $completed = false;
/**
* @ManyToMany(targetEntity="CompanyEmployee")
* @ManyToMany(targetEntity="CompanyEmployee", inversedBy="contracts")
* @JoinTable(name="company_contract_employees",
* joinColumns={@JoinColumn(name="contract_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={@JoinColumn(name="employee_id", referencedColumnName="id")}
@ -86,4 +86,4 @@ abstract class CompanyContract
}
abstract public function calculatePrice();
}
}

View File

@ -23,6 +23,16 @@ class CompanyEmployee extends CompanyPerson
*/
private $startDate;
/**
* @ManyToMany(targetEntity="CompanyContract", mappedBy="engineers", fetch="EXTRA_LAZY")
*/
public $contracts;
/**
* @OneToMany(targetEntity="CompanyFlexUltraContract", mappedBy="salesPerson", fetch="EXTRA_LAZY")
*/
public $soldContracts;
public function getSalary() {
return $this->salary;
}
@ -46,4 +56,4 @@ class CompanyEmployee extends CompanyPerson
public function setStartDate($date) {
$this->startDate = $date;
}
}
}

View File

@ -18,6 +18,15 @@ class CompanyFlexContract extends CompanyContract
*/
private $pricePerHour = 0;
/**
* @ManyToMany(targetEntity="CompanyManager", inversedBy="managedContracts", fetch="EXTRA_LAZY")
* @JoinTable(name="company_contract_managers",
* joinColumns={@JoinColumn(name="contract_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={@JoinColumn(name="employee_id", referencedColumnName="id")}
* )
*/
public $managers;
public function calculatePrice()
{
return $this->hoursWorked * $this->pricePerHour;
@ -42,4 +51,18 @@ class CompanyFlexContract extends CompanyContract
{
$this->pricePerHour = $pricePerHour;
}
}
public function getManagers()
{
return $this->managers;
}
public function addManager(CompanyManager $manager)
{
$this->managers[] = $manager;
}
public function removeManager(CompanyManager $manager)
{
$this->managers->removeElement($manager);
}
}

View File

@ -19,6 +19,11 @@ class CompanyManager extends CompanyEmployee
*/
private $car;
/**
* @ManyToMany(targetEntity="CompanyFlexContract", mappedBy="managers", fetch="EXTRA_LAZY")
*/
public $managedContracts;
public function getTitle() {
return $this->title;
}
@ -34,4 +39,4 @@ class CompanyManager extends CompanyEmployee
public function setCar(CompanyCar $car) {
$this->car = $car;
}
}
}

View File

@ -11,9 +11,9 @@ class CompanyOrganization {
private $id;
/**
* @OneToMany(targetEntity="CompanyEvent", mappedBy="organization", cascade={"persist"})
* @OneToMany(targetEntity="CompanyEvent", mappedBy="organization", cascade={"persist"}, fetch="EXTRA_LAZY")
*/
private $events;
public $events;
public function getId() {
return $this->id;
@ -41,4 +41,4 @@ class CompanyOrganization {
public function setMainEvent($event) {
$this->mainevent = $event;
}
}
}

View File

@ -114,10 +114,10 @@ class EntityManagerTest extends \Doctrine\Tests\OrmTestCase
/**
* @dataProvider dataMethodsAffectedByNoObjectArguments
* @expectedException \InvalidArgumentException
* @param string $methodName
*/
public function testThrowsExceptionOnNonObjectValues($methodName) {
$this->setExpectedException('Doctrine\ORM\ORMInvalidArgumentException',
'EntityManager#'.$methodName.'() expects parameter 1 to be an entity object, NULL given.');
$this->_em->$methodName(null);
}

View File

@ -71,7 +71,7 @@ class LockTest extends \Doctrine\Tests\OrmFunctionalTestCase {
public function testLockUnmanagedEntity_ThrowsException() {
$article = new CmsArticle();
$this->setExpectedException('InvalidArgumentException', 'Entity is not MANAGED.');
$this->setExpectedException('InvalidArgumentException', 'Entity Doctrine\Tests\Models\CMS\CmsArticle');
$this->_em->lock($article, LockMode::OPTIMISTIC, $article->version + 1);
}

View File

@ -167,20 +167,21 @@ class QueryDqlFunctionTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testFunctionSubstring()
{
$dql = "SELECT m, SUBSTRING(m.name, 1, 3) AS str1, SUBSTRING(m.name, 5) AS str2 ".
"FROM Doctrine\Tests\Models\Company\CompanyManager m";
"FROM Doctrine\Tests\Models\Company\CompanyManager m ORDER BY m.name";
$result = $this->_em->createQuery($dql)
->getArrayResult();
$this->assertEquals(4, count($result));
$this->assertEquals('Rom', $result[0]['str1']);
$this->assertEquals('Ben', $result[1]['str1']);
$this->assertEquals('Gui', $result[2]['str1']);
$this->assertEquals('Jon', $result[3]['str1']);
$this->assertEquals('n B.', $result[0]['str2']);
$this->assertEquals('amin E.', $result[1]['str2']);
$this->assertEquals('herme B.', $result[2]['str2']);
$this->assertEquals('than W.', $result[3]['str2']);
$this->assertEquals('Ben', $result[0]['str1']);
$this->assertEquals('Gui', $result[1]['str1']);
$this->assertEquals('Jon', $result[2]['str1']);
$this->assertEquals('Rom', $result[3]['str1']);
$this->assertEquals('amin E.', $result[0]['str2']);
$this->assertEquals('herme B.', $result[1]['str2']);
$this->assertEquals('than W.', $result[2]['str2']);
$this->assertEquals('n B.', $result[3]['str2']);
}
public function testFunctionTrim()

View File

@ -87,7 +87,7 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->flush();
$this->_em->clear();
$query = $this->_em->createQuery("select u, a from Doctrine\Tests\Models\CMS\CmsUser u join u.articles a");
$query = $this->_em->createQuery("select u, a from Doctrine\Tests\Models\CMS\CmsUser u join u.articles a ORDER BY a.topic");
$users = $query->getResult();
$this->assertEquals(1, count($users));
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]);

View File

@ -19,6 +19,8 @@ use Doctrine\Tests\Models\CMS\CmsComment;
use Doctrine\Tests\Models\Company\CompanyPerson;
use Doctrine\Tests\Models\Company\CompanyManager;
use Doctrine\Tests\Models\Company\CompanyEmployee;
use Doctrine\Tests\Models\Company\CompanyOrganization;
use Doctrine\Tests\Models\Company\CompanyAuction;
use Doctrine\Tests\Models\Company\CompanyFlexContract;
use Doctrine\Tests\Models\Company\CompanyFlexUltraContract;
@ -34,6 +36,8 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
private $userId, $userId2, $articleId, $articleId2;
private $groupId, $groupId2;
private $managerId, $managerId2, $contractId1, $contractId2;
private $organizationId, $eventId1, $eventId2;
public function setUp()
{
@ -552,11 +556,7 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(2, count($this->_em->createQuery("SELECT cm FROM Doctrine\Tests\Models\Company\CompanyManager cm")->getResult()));
// Enable the filter
$conf = $this->_em->getConfiguration();
$conf->addFilter("person_name", "\Doctrine\Tests\ORM\Functional\CompanyPersonNameFilter");
$this->_em->getFilters()
->enable("person_name")
->setParameter("name", "Guilh%", DBALType::STRING);
$this->usePersonNameFilter('Guilh%');
$managers = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyManager')->findAll();
$this->assertEquals(1, count($managers));
@ -572,11 +572,7 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals(3, count($this->_em->createQuery("SELECT cp FROM Doctrine\Tests\Models\Company\CompanyPerson cp")->getResult()));
// Enable the filter
$conf = $this->_em->getConfiguration();
$conf->addFilter("person_name", "\Doctrine\Tests\ORM\Functional\CompanyPersonNameFilter");
$this->_em->getFilters()
->enable("person_name")
->setParameter("name", "Guilh%", DBALType::STRING);
$this->usePersonNameFilter('Guilh%');
$persons = $this->_em->getRepository('Doctrine\Tests\Models\Company\CompanyPerson')->findAll();
$this->assertEquals(1, count($persons));
@ -655,12 +651,302 @@ class SQLFilterTest extends \Doctrine\Tests\OrmFunctionalTestCase
$contract4 = new CompanyFlexContract;
$contract4->markCompleted();
$manager = new CompanyManager;
$manager->setName('Alexander');
$manager->setSalary(42);
$manager->setDepartment('Doctrine');
$manager->setTitle('Filterer');
$manager2 = new CompanyManager;
$manager2->setName('Benjamin');
$manager2->setSalary(1337);
$manager2->setDepartment('Doctrine');
$manager2->setTitle('Maintainer');
$contract1->addManager($manager);
$contract2->addManager($manager);
$contract3->addManager($manager);
$contract4->addManager($manager);
$contract1->addManager($manager2);
$contract1->setSalesPerson($manager);
$contract2->setSalesPerson($manager);
$this->_em->persist($manager);
$this->_em->persist($manager2);
$this->_em->persist($contract1);
$this->_em->persist($contract2);
$this->_em->persist($contract3);
$this->_em->persist($contract4);
$this->_em->flush();
$this->_em->clear();
$this->managerId = $manager->getId();
$this->managerId2 = $manager2->getId();
$this->contractId1 = $contract1->getId();
$this->contractId2 = $contract2->getId();
}
private function useCompletedContractFilter()
{
$conf = $this->_em->getConfiguration();
$conf->addFilter("completed_contract", "\Doctrine\Tests\ORM\Functional\CompletedContractFilter");
$this->_em->getFilters()
->enable("completed_contract")
->setParameter("completed", true, DBALType::BOOLEAN);
}
public function testManyToMany_ExtraLazyCountWithFilterOnSTI()
{
$this->loadCompanySingleTableInheritanceFixtureData();
$manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId);
$this->assertFalse($manager->managedContracts->isInitialized());
$this->assertEquals(4, count($manager->managedContracts));
// Enable the filter
$this->useCompletedContractFilter();
$this->assertFalse($manager->managedContracts->isInitialized());
$this->assertEquals(2, count($manager->managedContracts));
}
public function testManyToMany_ExtraLazyContainsWithFilterOnSTI()
{
$this->loadCompanySingleTableInheritanceFixtureData();
$manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId);
$contract1 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->contractId1);
$contract2 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->contractId2);
$this->assertFalse($manager->managedContracts->isInitialized());
$this->assertTrue($manager->managedContracts->contains($contract1));
$this->assertTrue($manager->managedContracts->contains($contract2));
// Enable the filter
$this->useCompletedContractFilter();
$this->assertFalse($manager->managedContracts->isInitialized());
$this->assertFalse($manager->managedContracts->contains($contract1));
$this->assertTrue($manager->managedContracts->contains($contract2));
}
public function testManyToMany_ExtraLazySliceWithFilterOnSTI()
{
$this->loadCompanySingleTableInheritanceFixtureData();
$manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId);
$this->assertFalse($manager->managedContracts->isInitialized());
$this->assertEquals(4, count($manager->managedContracts->slice(0, 10)));
// Enable the filter
$this->useCompletedContractFilter();
$this->assertFalse($manager->managedContracts->isInitialized());
$this->assertEquals(2, count($manager->managedContracts->slice(0, 10)));
}
private function usePersonNameFilter($name)
{
// Enable the filter
$conf = $this->_em->getConfiguration();
$conf->addFilter("person_name", "\Doctrine\Tests\ORM\Functional\CompanyPersonNameFilter");
$this->_em->getFilters()
->enable("person_name")
->setParameter("name", $name, DBALType::STRING);
}
public function testManyToMany_ExtraLazyCountWithFilterOnCTI()
{
$this->loadCompanySingleTableInheritanceFixtureData();
$contract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyFlexUltraContract', $this->contractId1);
$this->assertFalse($contract->managers->isInitialized());
$this->assertEquals(2, count($contract->managers));
// Enable the filter
$this->usePersonNameFilter('Benjamin');
$this->assertFalse($contract->managers->isInitialized());
$this->assertEquals(1, count($contract->managers));
}
public function testManyToMany_ExtraLazyContainsWithFilterOnCTI()
{
$this->loadCompanySingleTableInheritanceFixtureData();
$contract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyFlexUltraContract', $this->contractId1);
$manager1 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId);
$manager2 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId2);
$this->assertFalse($contract->managers->isInitialized());
$this->assertTrue($contract->managers->contains($manager1));
$this->assertTrue($contract->managers->contains($manager2));
// Enable the filter
$this->usePersonNameFilter('Benjamin');
$this->assertFalse($contract->managers->isInitialized());
$this->assertFalse($contract->managers->contains($manager1));
$this->assertTrue($contract->managers->contains($manager2));
}
public function testManyToMany_ExtraLazySliceWithFilterOnCTI()
{
$this->loadCompanySingleTableInheritanceFixtureData();
$contract = $this->_em->find('Doctrine\Tests\Models\Company\CompanyFlexUltraContract', $this->contractId1);
$this->assertFalse($contract->managers->isInitialized());
$this->assertEquals(2, count($contract->managers->slice(0, 10)));
// Enable the filter
$this->usePersonNameFilter('Benjamin');
$this->assertFalse($contract->managers->isInitialized());
$this->assertEquals(1, count($contract->managers->slice(0, 10)));
}
public function testOneToMany_ExtraLazyCountWithFilterOnSTI()
{
$this->loadCompanySingleTableInheritanceFixtureData();
$manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId);
$this->assertFalse($manager->soldContracts->isInitialized());
$this->assertEquals(2, count($manager->soldContracts));
// Enable the filter
$this->useCompletedContractFilter();
$this->assertFalse($manager->soldContracts->isInitialized());
$this->assertEquals(1, count($manager->soldContracts));
}
public function testOneToMany_ExtraLazyContainsWithFilterOnSTI()
{
$this->loadCompanySingleTableInheritanceFixtureData();
$manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId);
$contract1 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->contractId1);
$contract2 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyContract', $this->contractId2);
$this->assertFalse($manager->soldContracts->isInitialized());
$this->assertTrue($manager->soldContracts->contains($contract1));
$this->assertTrue($manager->soldContracts->contains($contract2));
// Enable the filter
$this->useCompletedContractFilter();
$this->assertFalse($manager->soldContracts->isInitialized());
$this->assertFalse($manager->soldContracts->contains($contract1));
$this->assertTrue($manager->soldContracts->contains($contract2));
}
public function testOneToMany_ExtraLazySliceWithFilterOnSTI()
{
$this->loadCompanySingleTableInheritanceFixtureData();
$manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $this->managerId);
$this->assertFalse($manager->soldContracts->isInitialized());
$this->assertEquals(2, count($manager->soldContracts->slice(0, 10)));
// Enable the filter
$this->useCompletedContractFilter();
$this->assertFalse($manager->soldContracts->isInitialized());
$this->assertEquals(1, count($manager->soldContracts->slice(0, 10)));
}
private function loadCompanyOrganizationEventJoinedSubclassFixtureData()
{
$organization = new CompanyOrganization;
$event1 = new CompanyAuction;
$event1->setData('foo');
$event2 = new CompanyAuction;
$event2->setData('bar');
$organization->addEvent($event1);
$organization->addEvent($event2);
$this->_em->persist($organization);
$this->_em->flush();
$this->_em->clear();
$this->organizationId = $organization->getId();
$this->eventId1 = $event1->getId();
$this->eventId2 = $event2->getId();
}
private function useCompanyEventIdFilter()
{
// Enable the filter
$conf = $this->_em->getConfiguration();
$conf->addFilter("event_id", "\Doctrine\Tests\ORM\Functional\CompanyEventFilter");
$this->_em->getFilters()
->enable("event_id")
->setParameter("id", $this->eventId2);
}
public function testOneToMany_ExtraLazyCountWithFilterOnCTI()
{
$this->loadCompanyOrganizationEventJoinedSubclassFixtureData();
$organization = $this->_em->find('Doctrine\Tests\Models\Company\CompanyOrganization', $this->organizationId);
$this->assertFalse($organization->events->isInitialized());
$this->assertEquals(2, count($organization->events));
// Enable the filter
$this->useCompanyEventIdFilter();
$this->assertFalse($organization->events->isInitialized());
$this->assertEquals(1, count($organization->events));
}
public function testOneToMany_ExtraLazyContainsWithFilterOnCTI()
{
$this->loadCompanyOrganizationEventJoinedSubclassFixtureData();
$organization = $this->_em->find('Doctrine\Tests\Models\Company\CompanyOrganization', $this->organizationId);
$event1 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyEvent', $this->eventId1);
$event2 = $this->_em->find('Doctrine\Tests\Models\Company\CompanyEvent', $this->eventId2);
$this->assertFalse($organization->events->isInitialized());
$this->assertTrue($organization->events->contains($event1));
$this->assertTrue($organization->events->contains($event2));
// Enable the filter
$this->useCompanyEventIdFilter();
$this->assertFalse($organization->events->isInitialized());
$this->assertFalse($organization->events->contains($event1));
$this->assertTrue($organization->events->contains($event2));
}
public function testOneToMany_ExtraLazySliceWithFilterOnCTI()
{
$this->loadCompanyOrganizationEventJoinedSubclassFixtureData();
$organization = $this->_em->find('Doctrine\Tests\Models\Company\CompanyOrganization', $this->organizationId);
$this->assertFalse($organization->events->isInitialized());
$this->assertEquals(2, count($organization->events->slice(0, 10)));
// Enable the filter
$this->useCompanyEventIdFilter();
$this->assertFalse($organization->events->isInitialized());
$this->assertEquals(1, count($organization->events->slice(0, 10)));
}
}
@ -747,3 +1033,15 @@ class CompletedContractFilter extends SQLFilter
return $targetTableAlias.'.completed = ' . $this->getParameter('completed');
}
}
class CompanyEventFilter extends SQLFilter
{
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias, $targetTable = '')
{
if ($targetEntity->name != "Doctrine\Tests\Models\Company\CompanyEvent") {
return "";
}
return $targetTableAlias.'.id = ' . $this->getParameter('id');
}
}

View File

@ -63,6 +63,6 @@ class CompanySchemaTest extends \Doctrine\Tests\OrmFunctionalTestCase
$sql = $this->_schemaTool->getDropSchemaSQL(array(
$this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyManager'),
));
$this->assertEquals(3, count($sql));
$this->assertEquals(4, count($sql));
}
}
}

View File

@ -36,7 +36,8 @@ class DDC214Test extends \Doctrine\Tests\OrmFunctionalTestCase
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'Doctrine\Tests\Models\CMS\CmsAddress',
'Doctrine\Tests\Models\CMS\CmsGroup',
'Doctrine\Tests\Models\CMS\CmsArticle'
'Doctrine\Tests\Models\CMS\CmsArticle',
'Doctrine\Tests\Models\CMS\CmsEmail',
);
$this->assertCreatedSchemaNeedsNoUpdates($this->classes);

View File

@ -0,0 +1,37 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\OrmFunctionalTestCase;
/**
* @group DDC-1360
*/
class DDC1360Test extends OrmFunctionalTestCase
{
public function testSchemaDoubleQuotedCreate()
{
if ($this->_em->getConnection()->getDatabasePlatform()->getName() != "postgresql") {
$this->markTestSkipped("PostgreSQL only test.");
}
$sql = $this->_schemaTool->getCreateSchemaSQL(array(
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1360DoubleQuote')
));
$this->assertEquals(array(
'CREATE TABLE "user"."user" (id INT NOT NULL, PRIMARY KEY(id))',
'CREATE SEQUENCE "user".user_id_seq INCREMENT BY 1 MINVALUE 1 START 1',
), $sql);
}
}
/**
* @Entity @Table(name="`user`.`user`")
*/
class DDC1360DoubleQuote
{
/** @Id @GeneratedValue @Column(type="integer") */
public $id;
}

View File

@ -2,14 +2,12 @@
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\Models\Qelista\User;
use Doctrine\Tests\Models\Qelista\ShoppingList;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Tests\Models\CMS\CmsComment;
use Doctrine\Tests\Models\CMS\CmsArticle;
use Doctrine\Tests\Models\CMS\CmsUser;
require_once __DIR__ . '/../../../TestInit.php';
/**

View File

@ -46,6 +46,7 @@ class DDC1548E1
*/
public $rel;
}
/**
* @Entity
*/

View File

@ -61,4 +61,4 @@ class DDC168Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $theEmployee);
$this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $theEmployee->getSpouse());
}
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\CMS\CmsUser;
class UnitOfWorkLifecycleTest extends \Doctrine\Tests\OrmFunctionalTestCase
{
protected function setUp()
{
$this->useModelSet('cms');
parent::setUp();
}
public function testScheduleInsertManaged()
{
$user = new CmsUser();
$user->username = "beberlei";
$user->name = "Benjamin";
$user->status = "active";
$this->_em->persist($user);
$this->_em->flush();
$this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "A managed+dirty entity Doctrine\Tests\Models\CMS\CmsUser");
$this->_em->getUnitOfWork()->scheduleForInsert($user);
}
public function testScheduleInsertDeleted()
{
$user = new CmsUser();
$user->username = "beberlei";
$user->name = "Benjamin";
$user->status = "active";
$this->_em->persist($user);
$this->_em->flush();
$this->_em->remove($user);
$this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "Removed entity Doctrine\Tests\Models\CMS\CmsUser");
$this->_em->getUnitOfWork()->scheduleForInsert($user);
}
public function testScheduleInsertTwice()
{
$user = new CmsUser();
$user->username = "beberlei";
$user->name = "Benjamin";
$user->status = "active";
$this->_em->getUnitOfWork()->scheduleForInsert($user);
$this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "Entity Doctrine\Tests\Models\CMS\CmsUser");
$this->_em->getUnitOfWork()->scheduleForInsert($user);
}
public function testAddToIdentityMapWithoutIdentity()
{
$user = new CmsUser();
$this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "The given entity of type 'Doctrine\Tests\Models\CMS\CmsUser' (Doctrine\Tests\Models\CMS\CmsUser@");
$this->_em->getUnitOfWork()->registerManaged($user, array(), array());
}
public function testMarkReadOnlyNonManaged()
{
$user = new CmsUser();
$this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "Only managed entities can be marked or checked as read only. But Doctrine\Tests\Models\CMS\CmsUser@");
$this->_em->getUnitOfWork()->markReadOnly($user);
}
}

View File

@ -18,6 +18,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$mappingDriver = $this->_loadDriver();
$class = new ClassMetadata($entityClassName);
$class->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$mappingDriver->loadMetadataForClass($entityClassName, $class);
return $class;
@ -404,6 +405,29 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals("INT unsigned NOT NULL", $class->fieldMappings['id']['columnDefinition']);
$this->assertEquals("VARCHAR(255) NOT NULL", $class->fieldMappings['value']['columnDefinition']);
}
/**
* @group DDC-559
*/
public function testNamingStrategy()
{
$driver = $this->_loadDriver();
$em = $this->_getTestEntityManager();
$factory = new \Doctrine\ORM\Mapping\ClassMetadataFactory();
$em->getConfiguration()->setMetadataDriverImpl($driver);
$factory->setEntityManager($em);
$this->assertInstanceOf('Doctrine\ORM\Mapping\DefaultNamingStrategy', $em->getConfiguration()->getNamingStrategy());
$em->getConfiguration()->setNamingStrategy(new \Doctrine\ORM\Mapping\UnderscoreNamingStrategy(CASE_UPPER));
$this->assertInstanceOf('Doctrine\ORM\Mapping\UnderscoreNamingStrategy', $em->getConfiguration()->getNamingStrategy());
$class = $factory->getMetadataFor('Doctrine\Tests\Models\DDC1476\DDC1476EntityWithDefaultFieldType');
$this->assertEquals('ID', $class->columnNames['id']);
$this->assertEquals('NAME', $class->columnNames['name']);
$this->assertEquals('DDC1476ENTITY_WITH_DEFAULT_FIELD_TYPE', $class->table['name']);
}
}
/**
@ -691,4 +715,8 @@ class DDC1170Entity
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE);
}
}
}
class Address {}
class Phonenumber {}
class Group {}

View File

@ -15,6 +15,7 @@ class AnnotationDriverTest extends AbstractMappingDriverTest
public function testLoadMetadataForNonEntityThrowsException()
{
$cm = new ClassMetadata('stdClass');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$reader = new \Doctrine\Common\Annotations\AnnotationReader(new \Doctrine\Common\Cache\ArrayCache());
$annotationDriver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader);
@ -28,6 +29,7 @@ class AnnotationDriverTest extends AbstractMappingDriverTest
public function testColumnWithMissingTypeDefaultsToString()
{
$cm = new ClassMetadata('Doctrine\Tests\ORM\Mapping\ColumnWithoutType');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$annotationDriver = $this->_loadDriver();
$annotationDriver->loadMetadataForClass('Doctrine\Tests\ORM\Mapping\InvalidColumn', $cm);

View File

@ -91,6 +91,7 @@ class BasicInheritanceMappingTest extends \Doctrine\Tests\OrmTestCase
$class = $this->_factory->getMetadataFor(__NAMESPACE__ . '\\EntitySubClass2');
$class2 = unserialize(serialize($class));
$class2->wakeupReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->assertTrue(isset($class2->reflFields['mapped1']));
$this->assertTrue(isset($class2->reflFields['mapped2']));
@ -197,6 +198,7 @@ class MappedSuperclassBase {
private $mappedRelated1;
private $transient;
}
class MappedSuperclassRelated1 {}
/** @Entity */
class EntitySubClass2 extends MappedSuperclassBase {
@ -314,4 +316,4 @@ class MediumSuperclassEntity extends MediumSuperclassBase
class SubclassWithRepository extends \Doctrine\Tests\Models\DDC869\DDC869Payment
{
}
}

View File

@ -40,6 +40,7 @@ class ClassMetadataBuilderTest extends \Doctrine\Tests\OrmTestCase
public function setUp()
{
$this->cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$this->cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->builder = new ClassMetadataBuilder($this->cm);
}

View File

@ -27,9 +27,9 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$cm1 = $this->_createValidClassMetadata();
// SUT
$cmf = new ClassMetadataFactoryTestSubject();
$cmf = new \Doctrine\ORM\Mapping\ClassMetadataFactory();
$cmf->setEntityManager($entityManager);
$cmf->setMetadataForClass($cm1->name, $cm1);
$cmf->setMetadataFor($cm1->name, $cm1);
// Prechecks
$this->assertEquals(array(), $cm1->parentClasses);
@ -37,15 +37,16 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
$this->assertTrue($cm1->hasField('name'));
$this->assertEquals(2, count($cm1->associationMappings));
$this->assertEquals(ClassMetadata::GENERATOR_TYPE_AUTO, $cm1->generatorType);
$this->assertEquals('group', $cm1->table['name']);
// Go
$cm1 = $cmf->getMetadataFor($cm1->name);
$cmMap1 = $cmf->getMetadataFor($cm1->name);
$this->assertEquals('group', $cm1->table['name']);
$this->assertTrue($cm1->table['quoted']);
$this->assertEquals(array(), $cm1->parentClasses);
$this->assertTrue($cm1->hasField('name'));
$this->assertEquals(ClassMetadata::GENERATOR_TYPE_SEQUENCE, $cm1->generatorType);
$this->assertSame($cm1, $cmMap1);
$this->assertEquals('group', $cmMap1->table['name']);
$this->assertTrue($cmMap1->table['quoted']);
$this->assertEquals(array(), $cmMap1->parentClasses);
$this->assertTrue($cmMap1->hasField('name'));
}
public function testGetMetadataFor_ReturnsLoadedCustomIdGenerator()
@ -202,6 +203,7 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
*/
protected function _createValidClassMetadata()
{
// Self-made metadata
$cm1 = new ClassMetadata('Doctrine\Tests\ORM\Mapping\TestEntity1');
$cm1->setPrimaryTable(array('name' => '`group`'));
// Add a mapped field

View File

@ -13,6 +13,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testClassMetadataInstanceSerialization()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
// Test initial state
$this->assertTrue(count($cm->getReflectionProperties()) == 0);
@ -29,13 +30,14 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$cm->setParentClasses(array("UserParent"));
$cm->setCustomRepositoryClass("UserRepository");
$cm->setDiscriminatorColumn(array('name' => 'disc', 'type' => 'integer'));
$cm->mapOneToOne(array('fieldName' => 'phonenumbers', 'targetEntity' => 'Bar', 'mappedBy' => 'foo'));
$cm->mapOneToOne(array('fieldName' => 'phonenumbers', 'targetEntity' => 'CmsAddress', 'mappedBy' => 'foo'));
$cm->markReadOnly();
$cm->addNamedQuery(array('name' => 'dql', 'query' => 'foo'));
$this->assertEquals(1, count($cm->associationMappings));
$serialized = serialize($cm);
$cm = unserialize($serialized);
$cm->wakeupReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
// Check state
$this->assertTrue(count($cm->getReflectionProperties()) > 0);
@ -52,7 +54,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$oneOneMapping = $cm->getAssociationMapping('phonenumbers');
$this->assertTrue($oneOneMapping['fetch'] == ClassMetadata::FETCH_LAZY);
$this->assertEquals('phonenumbers', $oneOneMapping['fieldName']);
$this->assertEquals('Doctrine\Tests\Models\CMS\Bar', $oneOneMapping['targetEntity']);
$this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddress', $oneOneMapping['targetEntity']);
$this->assertTrue($cm->isReadOnly);
$this->assertEquals(array('dql' => array('name'=>'dql','query'=>'foo','dql'=>'foo')), $cm->namedQueries);
}
@ -60,6 +62,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testFieldIsNullable()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
// Explicit Nullable
$cm->mapField(array('fieldName' => 'status', 'nullable' => true, 'type' => 'string', 'length' => 50));
@ -82,6 +85,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php";
$cm = new ClassMetadata('DoctrineGlobal_Article');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapManyToMany(array(
'fieldName' => 'author',
'targetEntity' => 'DoctrineGlobal_User',
@ -98,6 +102,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testMapManyToManyJoinTableDefaults()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapManyToMany(
array(
'fieldName' => 'groups',
@ -117,6 +122,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testSerializeManyToManyJoinTableCascade()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapManyToMany(
array(
'fieldName' => 'groups',
@ -138,6 +144,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php";
$cm = new ClassMetadata('DoctrineGlobal_User');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->setDiscriminatorMap(array('descr' => 'DoctrineGlobal_Article', 'foo' => 'DoctrineGlobal_User'));
$this->assertEquals("DoctrineGlobal_Article", $cm->discriminatorMap['descr']);
@ -152,6 +159,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
require_once __DIR__."/../../Models/Global/GlobalNamespaceModel.php";
$cm = new ClassMetadata('DoctrineGlobal_User');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->setSubclasses(array('DoctrineGlobal_Article'));
$this->assertEquals("DoctrineGlobal_Article", $cm->subClasses[0]);
@ -167,6 +175,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$field['type'] = 'string';
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
$cm->setVersionMapping($field);
@ -175,6 +184,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testGetSingleIdentifierFieldName_MultipleIdentifierEntity_ThrowsException()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->isIdentifierComposite = true;
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
@ -184,6 +194,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testDuplicateAssociationMappingException()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$a1 = array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo');
$a2 = array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo');
@ -195,6 +207,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testDuplicateColumnName_ThrowsMappingException()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapField(array('fieldName' => 'name', 'columnName' => 'name'));
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
@ -204,6 +218,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testDuplicateColumnName_DiscriminatorColumn_ThrowsMappingException()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapField(array('fieldName' => 'name', 'columnName' => 'name'));
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
@ -213,6 +229,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testDuplicateColumnName_DiscriminatorColumn2_ThrowsMappingException()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->setDiscriminatorColumn(array('name' => 'name'));
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
@ -222,6 +240,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testDuplicateFieldAndAssocationMapping1_ThrowsException()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapField(array('fieldName' => 'name', 'columnName' => 'name'));
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
@ -231,6 +251,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testDuplicateFieldAndAssocationMapping2_ThrowsException()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapOneToOne(array('fieldName' => 'name', 'targetEntity' => 'CmsUser'));
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
@ -243,6 +265,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testGetTemporaryTableNameSchema()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->setTableName('foo.bar');
$this->assertEquals('foo_bar_id_tmp', $cm->getTemporaryIdTableName());
@ -251,6 +275,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testDefaultTableName()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
// When table's name is not given
$primaryTable = array();
@ -260,6 +285,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('CmsUser', $cm->table['name']);
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
// When joinTable's name is not given
$cm->mapManyToMany(array(
'fieldName' => 'user',
@ -273,6 +299,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testDefaultJoinColumnName()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
// this is really dirty, but it's the simpliest way to test whether
// joinColumn's name will be automatically set to user_id
$cm->mapOneToOne(array(
@ -282,6 +310,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('user_id', $cm->associationMappings['user']['joinColumns'][0]['name']);
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapManyToMany(array(
'fieldName' => 'user',
'targetEntity' => 'CmsUser',
@ -293,12 +322,59 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('cmsuser_id', $cm->associationMappings['user']['joinTable']['inverseJoinColumns'][0]['name']);
}
/**
* @group DDC-559
*/
public function testUnderscoreNamingStrategyDefaults()
{
$namingStrategy = new \Doctrine\ORM\Mapping\UnderscoreNamingStrategy(CASE_UPPER);
$oneToOneMetadata = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', $namingStrategy);
$manyToManyMetadata = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsAddress', $namingStrategy);
$oneToOneMetadata->mapOneToOne(array(
'fieldName' => 'user',
'targetEntity' => 'CmsUser'
));
$manyToManyMetadata->mapManyToMany(array(
'fieldName' => 'user',
'targetEntity' => 'CmsUser'
));
$this->assertEquals(array('USER_ID'=>'ID'), $oneToOneMetadata->associationMappings['user']['sourceToTargetKeyColumns']);
$this->assertEquals(array('USER_ID'=>'USER_ID'), $oneToOneMetadata->associationMappings['user']['joinColumnFieldNames']);
$this->assertEquals(array('ID'=>'USER_ID'), $oneToOneMetadata->associationMappings['user']['targetToSourceKeyColumns']);
$this->assertEquals('USER_ID', $oneToOneMetadata->associationMappings['user']['joinColumns'][0]['name']);
$this->assertEquals('ID', $oneToOneMetadata->associationMappings['user']['joinColumns'][0]['referencedColumnName']);
$this->assertEquals('CMS_ADDRESS_CMS_USER', $manyToManyMetadata->associationMappings['user']['joinTable']['name']);
$this->assertEquals(array('CMS_ADDRESS_ID','CMS_USER_ID'), $manyToManyMetadata->associationMappings['user']['joinTableColumns']);
$this->assertEquals(array('CMS_ADDRESS_ID'=>'ID'), $manyToManyMetadata->associationMappings['user']['relationToSourceKeyColumns']);
$this->assertEquals(array('CMS_USER_ID'=>'ID'), $manyToManyMetadata->associationMappings['user']['relationToTargetKeyColumns']);
$this->assertEquals('CMS_ADDRESS_ID', $manyToManyMetadata->associationMappings['user']['joinTable']['joinColumns'][0]['name']);
$this->assertEquals('CMS_USER_ID', $manyToManyMetadata->associationMappings['user']['joinTable']['inverseJoinColumns'][0]['name']);
$this->assertEquals('ID', $manyToManyMetadata->associationMappings['user']['joinTable']['joinColumns'][0]['referencedColumnName']);
$this->assertEquals('ID', $manyToManyMetadata->associationMappings['user']['joinTable']['inverseJoinColumns'][0]['referencedColumnName']);
$cm = new ClassMetadata('DoctrineGlobal_Article', $namingStrategy);
$cm->mapManyToMany(array('fieldName' => 'author', 'targetEntity' => 'Doctrine\Tests\Models\CMS\CmsUser'));
$this->assertEquals('DOCTRINE_GLOBAL_ARTICLE_CMS_USER', $cm->associationMappings['author']['joinTable']['name']);
}
/**
* @group DDC-886
*/
public function testSetMultipleIdentifierSetsComposite()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapField(array('fieldName' => 'name'));
$cm->mapField(array('fieldName' => 'username'));
@ -312,6 +388,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testMappingNotFound()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException', "No mapping found for field 'foo' on class 'Doctrine\Tests\Models\CMS\CmsUser'.");
$cm->getFieldMapping('foo');
@ -323,6 +400,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testJoinTableMappingDefaults()
{
$cm = new ClassMetadata('DoctrineGlobal_Article');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapManyToMany(array('fieldName' => 'author', 'targetEntity' => 'Doctrine\Tests\Models\CMS\CmsUser'));
$this->assertEquals('doctrineglobal_article_cmsuser', $cm->associationMappings['author']['joinTable']['name']);
@ -334,6 +413,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testMapIdentifierAssociation()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapOneToOne(array(
'fieldName' => 'article',
'id' => true,
@ -351,6 +432,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testOrphanRemovalIdentifierAssociation()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'The orphan removal option is not allowed on an association that');
$cm->mapOneToOne(array(
@ -368,6 +450,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testInverseIdentifierAssocation()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'An inverse association is not allowed to be identifier in');
$cm->mapOneToOne(array(
@ -385,6 +469,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testIdentifierAssocationManyToMany()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'Many-to-many or one-to-many associations are not allowed to be identifier in');
$cm->mapManyToMany(array(
@ -403,12 +489,16 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException',
"The field or association mapping misses the 'fieldName' attribute in entity 'Doctrine\Tests\Models\CMS\CmsUser'.");
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapField(array('fieldName' => ''));
}
public function testRetrievalOfNamedQueries()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->assertEquals(0, count($cm->getNamedQueries()));
@ -423,6 +513,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testExistanceOfNamedQuery()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->addNamedQuery(array(
'name' => 'all',
@ -436,6 +528,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testRetrieveOfNamedQuery()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->addNamedQuery(array(
'name' => 'userById',
@ -448,6 +542,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testNamingCollisionNamedQueryShouldThrowException()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');
@ -469,6 +565,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
{
$user = new \Doctrine\Tests\Models\CMS\CmsUser();
$cm = new ClassMetadata('DOCTRINE\TESTS\MODELS\CMS\CMSUSER');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$this->assertEquals('Doctrine\Tests\Models\CMS\CmsUser', $cm->name);
}
@ -478,8 +576,23 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testLifecycleCallbackNotFound()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->addLifecycleCallback('notfound', 'postLoad');
$this->setExpectedException("Doctrine\ORM\Mapping\MappingException", "Entity 'Doctrine\Tests\Models\CMS\CmsUser' has no method 'notfound' to be registered as lifecycle callback.");
$cm->addLifecycleCallback('notfound', 'postLoad');
$cm->validateLifecycleCallbacks(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
}
/**
* @group ImproveErrorMessages
*/
public function testTargetEntityNotFound()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$cm->mapManyToOne(array('fieldName' => 'address', 'targetEntity' => 'UnknownClass'));
$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();
}
}

View File

@ -0,0 +1,298 @@
<?php
namespace Doctrine\Tests\ORM\Mapping;
use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
use Doctrine\ORM\Mapping\DefaultNamingStrategy;
use Doctrine\ORM\Mapping\NamingStrategy;
require_once __DIR__ . '/../../TestInit.php';
/**
* @group DDC-559
*/
class NamingStrategyTest extends \Doctrine\Tests\OrmTestCase
{
/**
* @return DefaultNamingStrategy
*/
static private function defaultNaming()
{
return new DefaultNamingStrategy();
}
/**
* @return UnderscoreNamingStrategy
*/
static private function underscoreNamingLower()
{
return new UnderscoreNamingStrategy(CASE_LOWER);
}
/**
* @return UnderscoreNamingStrategy
*/
static private function underscoreNamingUpper()
{
return new UnderscoreNamingStrategy(CASE_UPPER);
}
/**
* Data Provider for NamingStrategy#classToTableName
*
* @return array
*/
static public function dataClassToTableName()
{
return array(
// DefaultNamingStrategy
array(self::defaultNaming(), 'SomeClassName',
'SomeClassName'
),
array(self::defaultNaming(), 'SomeClassName',
'\SomeClassName'
),
array(self::defaultNaming(), 'Name',
'\Some\Class\Name'
),
// UnderscoreNamingStrategy
array(self::underscoreNamingLower(), 'some_class_name',
'\Name\Space\SomeClassName'
),
array(self::underscoreNamingLower(), 'name',
'\Some\Class\Name'
),
array(self::underscoreNamingUpper(), 'SOME_CLASS_NAME',
'\Name\Space\SomeClassName'
),
array(self::underscoreNamingUpper(), 'NAME',
'\Some\Class\Name'
),
);
}
/**
* @dataProvider dataClassToTableName
*/
public function testClassToTableName(NamingStrategy $strategy, $expected, $className)
{
$this->assertEquals($expected, $strategy->classToTableName($className));
}
/**
* Data Provider for NamingStrategy#propertyToColumnName
*
* @return array
*/
static public function dataPropertyToColumnName()
{
return array(
// DefaultNamingStrategy
array(self::defaultNaming(), 'someProperty',
'someProperty'
),
array(self::defaultNaming(), 'SOME_PROPERTY',
'SOME_PROPERTY'
),
array(self::defaultNaming(), 'some_property',
'some_property'
),
// UnderscoreNamingStrategy
array(self::underscoreNamingLower(), 'some_property',
'someProperty'
),
array(self::underscoreNamingUpper(), 'SOME_PROPERTY',
'someProperty'
),
array(self::underscoreNamingUpper(), 'SOME_PROPERTY',
'some_property'
),
array(self::underscoreNamingUpper(), 'SOME_PROPERTY',
'SOME_PROPERTY'
),
);
}
/**
* @dataProvider dataPropertyToColumnName
*
* @param NamingStrategy $strategy
* @param string $expected
* @param string $propertyName
*/
public function testPropertyToColumnName(NamingStrategy $strategy, $expected, $propertyName)
{
$this->assertEquals($expected, $strategy->propertyToColumnName($propertyName));
}
/**
* Data Provider for NamingStrategy#referenceColumnName
*
* @return array
*/
static public function dataReferenceColumnName()
{
return array(
// DefaultNamingStrategy
array(self::defaultNaming(), 'id'),
// UnderscoreNamingStrategy
array(self::underscoreNamingLower(), 'id'),
array(self::underscoreNamingUpper(), 'ID'),
);
}
/**
* @dataProvider dataReferenceColumnName
*
* @param NamingStrategy $strategy
* @param string $expected
*/
public function testReferenceColumnName(NamingStrategy $strategy, $expected)
{
$this->assertEquals($expected, $strategy->referenceColumnName());
}
/**
* Data Provider for NamingStrategy#joinColumnName
*
* @return array
*/
static public function dataJoinColumnName()
{
return array(
// DefaultNamingStrategy
array(self::defaultNaming(), 'someColumn_id',
'someColumn', null,
),
array(self::defaultNaming(), 'some_column_id',
'some_column', null,
),
// UnderscoreNamingStrategy
array(self::underscoreNamingLower(), 'some_column_id',
'someColumn', null,
),
array(self::underscoreNamingUpper(), 'SOME_COLUMN_ID',
'someColumn', null,
),
);
}
/**
* @dataProvider dataJoinColumnName
*
* @param NamingStrategy $strategy
* @param string $expected
* @param string $propertyName
*/
public function testJoinColumnName(NamingStrategy $strategy, $expected, $propertyName)
{
$this->assertEquals($expected, $strategy->joinColumnName($propertyName));
}
/**
* Data Provider for NamingStrategy#joinTableName
*
* @return array
*/
static public function dataJoinTableName()
{
return array(
// DefaultNamingStrategy
array(self::defaultNaming(), 'someclassname_classname',
'SomeClassName', 'Some\ClassName', null,
),
array(self::defaultNaming(), 'someclassname_classname',
'\SomeClassName', 'ClassName', null,
),
array(self::defaultNaming(), 'name_classname',
'\Some\Class\Name', 'ClassName', null,
),
// UnderscoreNamingStrategy
array(self::underscoreNamingLower(), 'some_class_name_class_name',
'SomeClassName', 'Some\ClassName', null,
),
array(self::underscoreNamingLower(), 'some_class_name_class_name',
'\SomeClassName', 'ClassName', null,
),
array(self::underscoreNamingLower(), 'name_class_name',
'\Some\Class\Name', 'ClassName', null,
),
array(self::underscoreNamingUpper(), 'SOME_CLASS_NAME_CLASS_NAME',
'SomeClassName', 'Some\ClassName', null,
),
array(self::underscoreNamingUpper(), 'SOME_CLASS_NAME_CLASS_NAME',
'\SomeClassName', 'ClassName', null,
),
array(self::underscoreNamingUpper(), 'NAME_CLASS_NAME',
'\Some\Class\Name', 'ClassName', null,
),
);
}
/**
* @dataProvider dataJoinTableName
*
* @param NamingStrategy $strategy
* @param string $expected
* @param string $ownerEntity
* @param string $associatedEntity
* @param string $propertyName
*/
public function testJoinTableName(NamingStrategy $strategy, $expected, $ownerEntity, $associatedEntity, $propertyName = null)
{
$this->assertEquals($expected, $strategy->joinTableName($ownerEntity, $associatedEntity, $propertyName));
}
/**
* Data Provider for NamingStrategy#joinKeyColumnName
*
* @return array
*/
static public function dataJoinKeyColumnName()
{
return array(
// DefaultNamingStrategy
array(self::defaultNaming(), 'someclassname_id',
'SomeClassName', null, null,
),
array(self::defaultNaming(), 'name_identifier',
'\Some\Class\Name', 'identifier', null,
),
// UnderscoreNamingStrategy
array(self::underscoreNamingLower(), 'some_class_name_id',
'SomeClassName', null, null,
),
array(self::underscoreNamingLower(), 'class_name_identifier',
'\Some\Class\ClassName', 'identifier', null,
),
array(self::underscoreNamingUpper(), 'SOME_CLASS_NAME_ID',
'SomeClassName', null, null,
),
array(self::underscoreNamingUpper(), 'CLASS_NAME_IDENTIFIER',
'\Some\Class\ClassName', 'IDENTIFIER', null,
),
);
}
/**
* @dataProvider dataJoinKeyColumnName
*
* @param NamingStrategy $strategy
* @param string $expected
* @param string $propertyEntityName
* @param string $referencedColumnName
* @param string $propertyName
*/
public function testJoinKeyColumnName(NamingStrategy $strategy, $expected, $propertyEntityName, $referencedColumnName = null, $propertyName = null)
{
$this->assertEquals($expected, $strategy->joinKeyColumnName($propertyEntityName, $referencedColumnName, $propertyName));
}
}

View File

@ -21,6 +21,7 @@ class XmlMappingDriverTest extends AbstractMappingDriverTest
$mappingDriver = $this->_loadDriver();
$class = new ClassMetadata($className);
$class->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$mappingDriver->loadMetadataForClass($className, $class);
$expectedMap = array(
@ -92,4 +93,4 @@ class CTI
class CTIFoo extends CTI {}
class CTIBar extends CTI {}
class CTIBaz extends CTI {}
class CTIBaz extends CTI {}

View File

@ -127,6 +127,7 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
$className = "\DoctrineOrmTestEntity";
$proxyName = "DoctrineOrmTestEntityProxy";
$classMetadata = new \Doctrine\ORM\Mapping\ClassMetadata($className);
$classMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$classMetadata->mapField(array('fieldName' => 'id', 'type' => 'integer'));
$classMetadata->setIdentifier(array('id'));
@ -143,6 +144,7 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
$className = "\Doctrine\Tests\ORM\Proxy\SleepClass";
$proxyName = "DoctrineTestsORMProxySleepClassProxy";
$classMetadata = new \Doctrine\ORM\Mapping\ClassMetadata($className);
$classMetadata->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$classMetadata->mapField(array('fieldName' => 'id', 'type' => 'integer'));
$classMetadata->setIdentifier(array('id'));

View File

@ -822,6 +822,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
/**
* @group DDC-339
* @group DDC-1572
*/
public function testStringFunctionLikeExpression()
{
@ -837,6 +838,20 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
"SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(UPPER(u.name), '_moo') LIKE :str",
"SELECT c0_.name AS name0 FROM cms_users c0_ WHERE UPPER(c0_.name) || '_moo' LIKE ?"
);
// DDC-1572
$this->assertSqlGeneration(
"SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE UPPER(u.name) LIKE UPPER(:str)",
"SELECT c0_.name AS name0 FROM cms_users c0_ WHERE UPPER(c0_.name) LIKE UPPER(?)"
);
$this->assertSqlGeneration(
"SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE UPPER(LOWER(u.name)) LIKE UPPER(LOWER(:str))",
"SELECT c0_.name AS name0 FROM cms_users c0_ WHERE UPPER(LOWER(c0_.name)) LIKE UPPER(LOWER(?))"
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a WITH a.topic LIKE u.name",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic LIKE c0_.name)"
);
}
/**
@ -1415,6 +1430,56 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
);
}
/**
* @group DDC-1539
*/
public function testParenthesesOnTheLeftHandOfComparison()
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u where ( (u.id + u.id) * u.id ) > 100',
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (c0_.id + c0_.id) * c0_.id > 100'
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u where (u.id + u.id) * u.id > 100',
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE (c0_.id + c0_.id) * c0_.id > 100'
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u where 100 < (u.id + u.id) * u.id ',
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE 100 < (c0_.id + c0_.id) * c0_.id'
);
}
/**
* @group DDC-1557
*/
public function testSupportsSubSqlFunction()
{
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.name IN ( SELECT TRIM(u2.name) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.name IN (SELECT TRIM(c1_.name) AS sclr4 FROM cms_users c1_)'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.name IN ( SELECT TRIM(u2.name) FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE LOWER(u2.name) LIKE \'%fabio%\')',
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.name IN (SELECT TRIM(c1_.name) AS sclr4 FROM cms_users c1_ WHERE LOWER(c1_.name) LIKE \'%fabio%\')'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.email IN ( SELECT TRIM(IDENTITY(u2.email)) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.email_id IN (SELECT TRIM(c1_.email_id) AS sclr4 FROM cms_users c1_)'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.email IN ( SELECT IDENTITY(u2.email) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.email_id IN (SELECT c1_.email_id AS sclr4 FROM cms_users c1_)'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE COUNT(u1.id) = ( SELECT SUM(u2.id) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE COUNT(c0_.id) = (SELECT SUM(c1_.id) AS dctrn__1 FROM cms_users c1_)'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE COUNT(u1.id) <= ( SELECT SUM(u2.id) + COUNT(u2.email) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE COUNT(c0_.id) <= (SELECT SUM(c1_.id) + COUNT(c1_.email_id) AS sclr4 FROM cms_users c1_)'
);
}
public function testCustomTypeValueSql()
{
if (DBALType::hasType('negative_to_positive')) {

View File

@ -167,6 +167,8 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
$book = $this->newInstance($metadata);
$cm = new \Doctrine\ORM\Mapping\ClassMetadata($metadata->name);
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$driver = $this->createAnnotationDriver();
$driver->loadMetadataForClass($cm->name, $cm);
@ -189,6 +191,8 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
$book = $this->newInstance($metadata);
$cm = new \Doctrine\ORM\Mapping\ClassMetadata($metadata->name);
$cm->initializeReflection(new \Doctrine\Common\Persistence\Mapping\RuntimeReflectionService);
$driver->loadMetadataForClass($cm->name, $cm);
$this->assertEquals($cm->columnNames, $metadata->columnNames);
@ -249,4 +253,4 @@ class
}
class EntityGeneratorAuthor {}
class EntityGeneratorComment {}
class EntityGeneratorComment {}

View File

@ -368,4 +368,17 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
return rmdir($path);
}
}
}
}
class Address
{
}
class Phonenumber
{
}
class Group
{
}

View File

@ -158,6 +158,7 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
if (isset($this->_usedModelSets['company'])) {
$conn->executeUpdate('DELETE FROM company_contract_employees');
$conn->executeUpdate('DELETE FROM company_contract_managers');
$conn->executeUpdate('DELETE FROM company_contracts');
$conn->executeUpdate('DELETE FROM company_persons_friends');
$conn->executeUpdate('DELETE FROM company_managers');
@ -294,7 +295,11 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
// the actual database platform used during execution has effect on some
// metadata mapping behaviors (like the choice of the ID generation).
if (is_null(self::$_metadataCacheImpl)) {
self::$_metadataCacheImpl = new \Doctrine\Common\Cache\ArrayCache;
if (isset($GLOBALS['DOCTRINE_CACHE_IMPL'])) {
self::$_metadataCacheImpl = new $GLOBALS['DOCTRINE_CACHE_IMPL'];
} else {
self::$_metadataCacheImpl = new \Doctrine\Common\Cache\ArrayCache;
}
}
if (is_null(self::$_queryCacheImpl)) {