Merge branch 'master' of github.com:doctrine/doctrine2
This commit is contained in:
commit
23560038b4
@ -1,6 +1,6 @@
|
||||
# Doctrine 2 ORM
|
||||
|
||||
Doctrine 2 is an object-relational mapper (ORM) for PHP 5.3.0+ that provides transparent persistence
|
||||
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
|
||||
is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL),
|
||||
inspired by Hibernates HQL. This provides developers with a powerful alternative to SQL that maintains flexibility
|
||||
|
@ -1,3 +1,14 @@
|
||||
# EntityManager#getPartialReference() creates read-only entity
|
||||
|
||||
Entities returned from EntityManager#getPartialReference() are now marked as read-only if they
|
||||
haven't been in the identity map before. This means objects of this kind never lead to changes
|
||||
in the UnitOfWork.
|
||||
|
||||
# Fields omitted in a partial DQL query or a native query are never updated
|
||||
|
||||
Fields of an entity that are not returned from a partial DQL Query or native SQL query
|
||||
will never be updated through an UPDATE statement.
|
||||
|
||||
# Removed support for onUpdate in @JoinColumn
|
||||
|
||||
The onUpdate foreign key handling makes absolutly no sense in an ORM. Additionally Oracle doesn't even support it. Support for it is removed.
|
||||
|
@ -150,7 +150,7 @@
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="CASCADE"/>
|
||||
<xs:enumeration value="RESTRICT"/>
|
||||
<xs:enumeration value="SET_NULL"/>
|
||||
<xs:enumeration value="SET NULL"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
|
@ -128,7 +128,7 @@ class EntityManager implements ObjectManager
|
||||
$this->metadataFactory = new $metadataFactoryClassName;
|
||||
$this->metadataFactory->setEntityManager($this);
|
||||
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
|
||||
|
||||
|
||||
$this->unitOfWork = new UnitOfWork($this);
|
||||
$this->proxyFactory = new ProxyFactory($this,
|
||||
$config->getProxyDir(),
|
||||
@ -203,18 +203,18 @@ class EntityManager implements ObjectManager
|
||||
public function transactional(Closure $func)
|
||||
{
|
||||
$this->conn->beginTransaction();
|
||||
|
||||
|
||||
try {
|
||||
$return = $func($this);
|
||||
|
||||
|
||||
$this->flush();
|
||||
$this->conn->commit();
|
||||
|
||||
|
||||
return $return ?: true;
|
||||
} catch (Exception $e) {
|
||||
$this->close();
|
||||
$this->conn->rollback();
|
||||
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
@ -244,7 +244,7 @@ class EntityManager implements ObjectManager
|
||||
*
|
||||
* The class name must be the fully-qualified class name without a leading backslash
|
||||
* (as it is returned by get_class($obj)) or an aliased class name.
|
||||
*
|
||||
*
|
||||
* Examples:
|
||||
* MyProject\Domain\User
|
||||
* sales:PriceRequest
|
||||
@ -413,6 +413,7 @@ class EntityManager implements ObjectManager
|
||||
$entity = $class->newInstance();
|
||||
$class->setIdentifierValues($entity, $identifier);
|
||||
$this->unitOfWork->registerManaged($entity, $identifier, array());
|
||||
$this->unitOfWork->markReadOnly($entity);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
@ -421,16 +422,11 @@ class EntityManager implements ObjectManager
|
||||
* Clears the EntityManager. All entities that are currently managed
|
||||
* by this EntityManager become detached.
|
||||
*
|
||||
* @param string $entityName
|
||||
* @param string $entityName if given, only entities of this type will get detached
|
||||
*/
|
||||
public function clear($entityName = null)
|
||||
{
|
||||
if ($entityName === null) {
|
||||
$this->unitOfWork->clear();
|
||||
} else {
|
||||
//TODO
|
||||
throw new ORMException("EntityManager#clear(\$entityName) not yet implemented.");
|
||||
}
|
||||
$this->unitOfWork->clear($entityName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -449,7 +445,7 @@ class EntityManager implements ObjectManager
|
||||
*
|
||||
* The entity will be entered into the database at or before transaction
|
||||
* commit or as a result of the flush operation.
|
||||
*
|
||||
*
|
||||
* NOTE: The persist operation always considers entities that are not yet known to
|
||||
* this EntityManager as NEW. Do not pass detached entities to the persist operation.
|
||||
*
|
||||
@ -632,7 +628,7 @@ class EntityManager implements ObjectManager
|
||||
|
||||
/**
|
||||
* Check if the Entity manager is open or closed.
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isOpen()
|
||||
@ -713,6 +709,18 @@ class EntityManager implements ObjectManager
|
||||
return $this->proxyFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to initialize a lazy loading proxy or persistent collection.
|
||||
*
|
||||
* This method is a no-op for other objects
|
||||
*
|
||||
* @param object $obj
|
||||
*/
|
||||
public function initializeObject($obj)
|
||||
{
|
||||
$this->unitOfWork->initializeObject($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create EntityManager instances.
|
||||
*
|
||||
|
@ -178,7 +178,7 @@ class EntityRepository implements ObjectRepository
|
||||
*/
|
||||
public function findOneBy(array $criteria)
|
||||
{
|
||||
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($criteria);
|
||||
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($criteria, null, null, array(), 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,8 +204,7 @@ class EntityRepository implements ObjectRepository
|
||||
);
|
||||
}
|
||||
|
||||
if ( !isset($arguments[0])) {
|
||||
// we dont even want to allow null at this point, because we cannot (yet) transform it into IS NULL.
|
||||
if (empty($arguments)) {
|
||||
throw ORMException::findByRequiresParameter($method.$by);
|
||||
}
|
||||
|
||||
|
110
lib/Doctrine/ORM/Event/EntityEventDelegator.php
Normal file
110
lib/Doctrine/ORM/Event/EntityEventDelegator.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?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\Event;
|
||||
|
||||
use \Doctrine\Common\EventSubscriber;
|
||||
use \LogicException;
|
||||
|
||||
/**
|
||||
* Delegate events only for certain entities they are registered for.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @since 2.2
|
||||
*/
|
||||
class EntityEventDelegator implements EventSubscriber
|
||||
{
|
||||
/**
|
||||
* Keeps track of all the event listeners.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $listeners = array();
|
||||
|
||||
/**
|
||||
* If frozen no new event listeners can be added.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $frozen = false;
|
||||
|
||||
/**
|
||||
* Adds an event listener that listens on the specified events.
|
||||
*
|
||||
* @param string|array $events The event(s) to listen on.
|
||||
* @param string|array $entities The entities to trigger this listener for
|
||||
* @param object $listener The listener object.
|
||||
*/
|
||||
public function addEventListener($events, $entities, $listener)
|
||||
{
|
||||
if ($this->frozen) {
|
||||
throw new LogicException("Cannot add event listeners after EntityEventDelegator::getSubscribedEvents() " .
|
||||
"is called once. This happens when you register the delegator with the event manager.");
|
||||
}
|
||||
|
||||
// Picks the hash code related to that listener
|
||||
$hash = spl_object_hash($listener);
|
||||
|
||||
foreach ((array) $events as $event) {
|
||||
// Overrides listener if a previous one was associated already
|
||||
// Prevents duplicate listeners on same event (same instance only)
|
||||
$this->listeners[$event][$hash] = array('listener' => $listener, 'entities' => array_flip((array)$entities));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an EventSubscriber. The subscriber is asked for all the events he is
|
||||
* interested in and added as a listener for these events.
|
||||
*
|
||||
* @param Doctrine\Common\EventSubscriber $subscriber The subscriber.
|
||||
*/
|
||||
public function addEventSubscriber(EventSubscriber $subscriber, $entities)
|
||||
{
|
||||
$this->addEventListener($subscriber->getSubscribedEvents(), $entities, $subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of events this subscriber wants to listen to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSubscribedEvents()
|
||||
{
|
||||
$this->frozen = true;
|
||||
return array_keys($this->listeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate the event to an appropriate listener
|
||||
*
|
||||
* @param $eventName
|
||||
* @param $event
|
||||
* @return void
|
||||
*/
|
||||
public function __call($eventName, $args)
|
||||
{
|
||||
$event = $args[0];
|
||||
foreach ($this->listeners[$eventName] AS $listenerData) {
|
||||
$class = get_class($event->getEntity());
|
||||
if (isset($listenerData['entities'][$class])) {
|
||||
$listenerData['listener']->$eventName($event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -36,12 +36,18 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $entityClass;
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\EntityManager $em
|
||||
*/
|
||||
public function __construct($em)
|
||||
public function __construct($em, $entityClass = null)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->entityClass = $entityClass;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,4 +57,24 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
||||
{
|
||||
return $this->em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the entity class that is cleared, or empty if all are cleared.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEntityClass()
|
||||
{
|
||||
return $this->entityClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if event clears all entities.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clearsAllEntities()
|
||||
{
|
||||
return $this->entityClass === null;
|
||||
}
|
||||
}
|
@ -53,14 +53,14 @@ class AssignedGenerator extends AbstractIdGenerator
|
||||
if (!$em->getUnitOfWork()->isInIdentityMap($value)) {
|
||||
throw ORMException::entityMissingForeignAssignedId($entity, $value);
|
||||
}
|
||||
|
||||
|
||||
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
|
||||
$identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value));
|
||||
} else {
|
||||
$identifier[$idField] = $value;
|
||||
}
|
||||
} else {
|
||||
throw ORMException::entityMissingAssignedId($entity);
|
||||
throw ORMException::entityMissingAssignedIdForField($entity, $idField);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -71,17 +71,17 @@ class AssignedGenerator extends AbstractIdGenerator
|
||||
if (!$em->getUnitOfWork()->isInIdentityMap($value)) {
|
||||
throw ORMException::entityMissingForeignAssignedId($entity, $value);
|
||||
}
|
||||
|
||||
|
||||
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
|
||||
$identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value));
|
||||
} else {
|
||||
$identifier[$idField] = $value;
|
||||
}
|
||||
} else {
|
||||
throw ORMException::entityMissingAssignedId($entity);
|
||||
throw ORMException::entityMissingAssignedIdForField($entity, $idField);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,6 +164,11 @@ abstract class AbstractHydrator
|
||||
* field names during this procedure as well as any necessary conversions on
|
||||
* the values applied.
|
||||
*
|
||||
* @param array $data SQL Result Row
|
||||
* @param array &$cache Cache for column to field result information
|
||||
* @param array &$id Dql-Alias => ID-Hash
|
||||
* @param array &$nonemptyComponents Does this DQL-Alias has at least one non NULL value?
|
||||
*
|
||||
* @return array An array with all the fields (name => value) of the data row,
|
||||
* grouped by their component alias.
|
||||
*/
|
||||
|
@ -92,6 +92,11 @@ class ArrayHydrator extends AbstractHydrator
|
||||
$parent = $this->_rsm->parentAliasMap[$dqlAlias];
|
||||
$path = $parent . '.' . $dqlAlias;
|
||||
|
||||
// missing parent data, skipping as RIGHT JOIN hydration is not supported.
|
||||
if ( ! isset($nonemptyComponents[$parent]) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get a reference to the right element in the result tree.
|
||||
// This element will get the associated element attached.
|
||||
if ($this->_rsm->isMixed && isset($this->_rootAliases[$parent])) {
|
||||
@ -154,6 +159,17 @@ class ArrayHydrator extends AbstractHydrator
|
||||
// It's a root result element
|
||||
|
||||
$this->_rootAliases[$dqlAlias] = true; // Mark as root
|
||||
|
||||
// if this row has a NULL value for the root result id then make it a null result.
|
||||
if ( ! isset($nonemptyComponents[$dqlAlias]) ) {
|
||||
if ($this->_rsm->isMixed) {
|
||||
$result[] = array(0 => null);
|
||||
} else {
|
||||
$result[] = null;
|
||||
}
|
||||
++$this->_resultCounter;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for an existing element
|
||||
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||
|
@ -302,6 +302,12 @@ class ObjectHydrator extends AbstractHydrator
|
||||
// seen for this parent-child relationship
|
||||
$path = $parentAlias . '.' . $dqlAlias;
|
||||
|
||||
// We have a RIGHT JOIN result here. Doctrine cannot hydrate RIGHT JOIN Object-Graphs
|
||||
if (!isset($nonemptyComponents[$parentAlias])) {
|
||||
// TODO: Add special case code where we hydrate the right join objects into identity map at least
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get a reference to the parent object to which the joined element belongs.
|
||||
if ($this->_rsm->isMixed && isset($this->_rootAliases[$parentAlias])) {
|
||||
$first = reset($this->_resultPointers);
|
||||
@ -408,6 +414,18 @@ class ObjectHydrator extends AbstractHydrator
|
||||
// PATH C: Its a root result element
|
||||
$this->_rootAliases[$dqlAlias] = true; // Mark as root alias
|
||||
|
||||
// if this row has a NULL value for the root result id then make it a null result.
|
||||
if ( ! isset($nonemptyComponents[$dqlAlias]) ) {
|
||||
if ($this->_rsm->isMixed) {
|
||||
$result[] = array(0 => null);
|
||||
} else {
|
||||
$result[] = null;
|
||||
}
|
||||
++$this->_resultCounter;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for existing result from the iterations before
|
||||
if ( ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||
$element = $this->_getEntity($rowData[$dqlAlias], $dqlAlias);
|
||||
if (isset($this->_rsm->indexByMap[$dqlAlias])) {
|
||||
|
@ -308,6 +308,10 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
|
||||
if ($parent && $parent->isInheritanceTypeSingleTable()) {
|
||||
$class->setPrimaryTable($parent->table);
|
||||
}
|
||||
|
||||
if ($parent && $parent->containsForeignIdentifier) {
|
||||
$class->containsForeignIdentifier = true;
|
||||
}
|
||||
|
||||
$class->setParentClasses($visited);
|
||||
|
||||
@ -490,6 +494,10 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
|
||||
*/
|
||||
public function isTransient($class)
|
||||
{
|
||||
if ( ! $this->initialized) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return $this->driver->isTransient($class);
|
||||
}
|
||||
}
|
||||
|
176
lib/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php
Normal file
176
lib/Doctrine/ORM/Mapping/Driver/SimplifiedXmlDriver.php
Normal file
@ -0,0 +1,176 @@
|
||||
<?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\Driver;
|
||||
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
|
||||
/**
|
||||
* XmlDriver that additionally looks for mapping information in a global file.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @license MIT
|
||||
*/
|
||||
class SimplifiedXmlDriver extends XmlDriver
|
||||
{
|
||||
protected $_prefixes = array();
|
||||
protected $_globalBasename;
|
||||
protected $_classCache;
|
||||
protected $_fileExtension = '.orm.xml';
|
||||
|
||||
public function __construct($prefixes)
|
||||
{
|
||||
$this->addNamespacePrefixes($prefixes);
|
||||
}
|
||||
|
||||
public function setGlobalBasename($file)
|
||||
{
|
||||
$this->_globalBasename = $file;
|
||||
}
|
||||
|
||||
public function getGlobalBasename()
|
||||
{
|
||||
return $this->_globalBasename;
|
||||
}
|
||||
|
||||
public function addNamespacePrefixes($prefixes)
|
||||
{
|
||||
$this->_prefixes = array_merge($this->_prefixes, $prefixes);
|
||||
$this->addPaths(array_flip($prefixes));
|
||||
}
|
||||
|
||||
public function getNamespacePrefixes()
|
||||
{
|
||||
return $this->_prefixes;
|
||||
}
|
||||
|
||||
public function isTransient($className)
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
// The mapping is defined in the global mapping file
|
||||
if (isset($this->_classCache[$className])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->_findMappingFile($className);
|
||||
|
||||
return false;
|
||||
} catch (MappingException $e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAllClassNames()
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
$classes = array();
|
||||
|
||||
if ($this->_paths) {
|
||||
foreach ((array) $this->_paths as $path) {
|
||||
if (!is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($path),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
$fileName = $file->getBasename($this->_fileExtension);
|
||||
|
||||
if ($fileName == $file->getBasename() || $fileName == $this->_globalBasename) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: All files found here means classes are not transient!
|
||||
if (isset($this->_prefixes[$path])) {
|
||||
$classes[] = $this->_prefixes[$path].'\\'.str_replace('.', '\\', $fileName);
|
||||
} else {
|
||||
$classes[] = str_replace('.', '\\', $fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($classes, array_keys($this->_classCache));
|
||||
}
|
||||
|
||||
public function getElement($className)
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
if (!isset($this->_classCache[$className])) {
|
||||
$this->_classCache[$className] = parent::getElement($className);
|
||||
}
|
||||
|
||||
return $this->_classCache[$className];
|
||||
}
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
$this->_classCache = array();
|
||||
if (null !== $this->_globalBasename) {
|
||||
foreach ($this->_paths as $path) {
|
||||
if (is_file($file = $path.'/'.$this->_globalBasename.$this->_fileExtension)) {
|
||||
$this->_classCache = array_merge($this->_classCache, $this->_loadMappingFile($file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function _findMappingFile($className)
|
||||
{
|
||||
$defaultFileName = str_replace('\\', '.', $className).$this->_fileExtension;
|
||||
foreach ($this->_paths as $path) {
|
||||
if (!isset($this->_prefixes[$path])) {
|
||||
if (is_file($path.DIRECTORY_SEPARATOR.$defaultFileName)) {
|
||||
return $path.DIRECTORY_SEPARATOR.$defaultFileName;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$prefix = $this->_prefixes[$path];
|
||||
|
||||
if (0 !== strpos($className, $prefix.'\\')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', '.').$this->_fileExtension;
|
||||
if (is_file($filename)) {
|
||||
return $filename;
|
||||
}
|
||||
|
||||
throw MappingException::mappingFileNotFound($className, $filename);
|
||||
}
|
||||
|
||||
throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1).$this->_fileExtension);
|
||||
}
|
||||
}
|
182
lib/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php
Normal file
182
lib/Doctrine/ORM/Mapping/Driver/SimplifiedYamlDriver.php
Normal file
@ -0,0 +1,182 @@
|
||||
<?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\Driver;
|
||||
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
|
||||
/**
|
||||
* YamlDriver that additionally looks for mapping information in a global file.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @license MIT
|
||||
*/
|
||||
class SimplifiedYamlDriver extends YamlDriver
|
||||
{
|
||||
protected $_prefixes = array();
|
||||
protected $_globalBasename;
|
||||
protected $_classCache;
|
||||
protected $_fileExtension = '.orm.yml';
|
||||
|
||||
public function __construct($prefixes)
|
||||
{
|
||||
$this->addNamespacePrefixes($prefixes);
|
||||
}
|
||||
|
||||
public function setGlobalBasename($file)
|
||||
{
|
||||
$this->_globalBasename = $file;
|
||||
}
|
||||
|
||||
public function getGlobalBasename()
|
||||
{
|
||||
return $this->_globalBasename;
|
||||
}
|
||||
|
||||
public function addNamespacePrefixes($prefixes)
|
||||
{
|
||||
$this->_prefixes = array_merge($this->_prefixes, $prefixes);
|
||||
$this->addPaths(array_flip($prefixes));
|
||||
}
|
||||
|
||||
public function addNamespacePrefix($prefix, $path)
|
||||
{
|
||||
$this->_prefixes[$path] = $prefix;
|
||||
}
|
||||
|
||||
|
||||
public function getNamespacePrefixes()
|
||||
{
|
||||
return $this->_prefixes;
|
||||
}
|
||||
|
||||
public function isTransient($className)
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
// The mapping is defined in the global mapping file
|
||||
if (isset($this->_classCache[$className])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->_findMappingFile($className);
|
||||
|
||||
return false;
|
||||
} catch (MappingException $e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAllClassNames()
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
$classes = array();
|
||||
|
||||
if ($this->_paths) {
|
||||
foreach ((array) $this->_paths as $path) {
|
||||
if (!is_dir($path)) {
|
||||
throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
|
||||
}
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($path),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
$fileName = $file->getBasename($this->_fileExtension);
|
||||
|
||||
if ($fileName == $file->getBasename() || $fileName == $this->_globalBasename) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: All files found here means classes are not transient!
|
||||
if (isset($this->_prefixes[$path])) {
|
||||
$classes[] = $this->_prefixes[$path].'\\'.str_replace('.', '\\', $fileName);
|
||||
} else {
|
||||
$classes[] = str_replace('.', '\\', $fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($classes, array_keys($this->_classCache));
|
||||
}
|
||||
|
||||
public function getElement($className)
|
||||
{
|
||||
if (null === $this->_classCache) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
if (!isset($this->_classCache[$className])) {
|
||||
$this->_classCache[$className] = parent::getElement($className);
|
||||
}
|
||||
|
||||
return $this->_classCache[$className];
|
||||
}
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
$this->_classCache = array();
|
||||
if (null !== $this->_globalBasename) {
|
||||
foreach ($this->_paths as $path) {
|
||||
if (is_file($file = $path.'/'.$this->_globalBasename.$this->_fileExtension)) {
|
||||
$this->_classCache = array_merge($this->_classCache, $this->_loadMappingFile($file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function _findMappingFile($className)
|
||||
{
|
||||
$defaultFileName = str_replace('\\', '.', $className).$this->_fileExtension;
|
||||
foreach ($this->_paths as $path) {
|
||||
if (!isset($this->_prefixes[$path])) {
|
||||
if (is_file($path.DIRECTORY_SEPARATOR.$defaultFileName)) {
|
||||
return $path.DIRECTORY_SEPARATOR.$defaultFileName;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$prefix = $this->_prefixes[$path];
|
||||
|
||||
if (0 !== strpos($className, $prefix.'\\')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filename = $path.'/'.strtr(substr($className, strlen($prefix)+1), '\\', '.').$this->_fileExtension;
|
||||
if (is_file($filename)) {
|
||||
return $filename;
|
||||
}
|
||||
|
||||
throw MappingException::mappingFileNotFound($className, $filename);
|
||||
}
|
||||
|
||||
throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1).$this->_fileExtension);
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@ class ORMException extends Exception
|
||||
return new self("It's a requirement to specify a Metadata Driver and pass it ".
|
||||
"to Doctrine\ORM\Configuration::setMetadataDriverImpl().");
|
||||
}
|
||||
|
||||
|
||||
public static function entityMissingForeignAssignedId($entity, $relatedEntity)
|
||||
{
|
||||
return new self(
|
||||
@ -46,15 +46,14 @@ class ORMException extends Exception
|
||||
);
|
||||
}
|
||||
|
||||
public static function entityMissingAssignedId($entity)
|
||||
public static function entityMissingAssignedIdForField($entity, $field)
|
||||
{
|
||||
return new self("Entity of type " . get_class($entity) . " is missing an assigned ID. " .
|
||||
return new self("Entity of type " . get_class($entity) . " is missing an assigned ID for field '" . $field . "'. " .
|
||||
"The identifier generation strategy for this entity requires the ID field to be populated before ".
|
||||
"EntityManager#persist() is called. If you want automatically generated identifiers instead " .
|
||||
"EntityManager#persist() is called. If you want automatically generated identifiers instead " .
|
||||
"you need to adjust the metadata mapping accordingly."
|
||||
);
|
||||
}
|
||||
|
||||
public static function unrecognizedField($field)
|
||||
{
|
||||
return new self("Unrecognized field: $field");
|
||||
@ -130,8 +129,8 @@ class ORMException extends Exception
|
||||
"Unknown Entity namespace alias '$entityNamespaceAlias'."
|
||||
);
|
||||
}
|
||||
|
||||
public static function invalidEntityRepository($className)
|
||||
|
||||
public static function invalidEntityRepository($className)
|
||||
{
|
||||
return new self("Invalid repository class '".$className."'. ".
|
||||
"it must be a Doctrine\ORM\EntityRepository.");
|
||||
|
@ -580,12 +580,13 @@ class BasicEntityPersister
|
||||
* @param $assoc The association that connects the entity to load to another entity, if any.
|
||||
* @param array $hints Hints for entity creation.
|
||||
* @param int $lockMode
|
||||
* @param int $limit Limit number of results
|
||||
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
|
||||
* @todo Check identity map? loadById method? Try to guess whether $criteria is the id?
|
||||
*/
|
||||
public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = 0)
|
||||
public function load(array $criteria, $entity = null, $assoc = null, array $hints = array(), $lockMode = 0, $limit = null)
|
||||
{
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, $lockMode);
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, $lockMode, $limit);
|
||||
list($params, $types) = $this->expandParameters($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params, $types);
|
||||
|
||||
@ -823,7 +824,7 @@ class BasicEntityPersister
|
||||
|
||||
if (isset($sourceClass->associationMappings[$field])) {
|
||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
||||
$value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
|
||||
}
|
||||
|
||||
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $value;
|
||||
@ -847,7 +848,7 @@ class BasicEntityPersister
|
||||
|
||||
if (isset($sourceClass->associationMappings[$field])) {
|
||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
||||
$value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
|
||||
}
|
||||
|
||||
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $value;
|
||||
@ -1060,10 +1061,10 @@ class BasicEntityPersister
|
||||
if ($columnList) $columnList .= ', ';
|
||||
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
|
||||
. '.' . $srcColumn . ' AS ' . $columnAlias;
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$this->_rsm->addMetaResult($alias, $this->_platform->getSQLResultCasing($columnAlias), $srcColumn, isset($assoc['id']) && $assoc['id'] === true);
|
||||
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
|
||||
. '.' . $srcColumn . ' AS ' . $resultColumnName;
|
||||
$this->_rsm->addMetaResult($alias, $resultColumnName, $srcColumn, isset($assoc['id']) && $assoc['id'] === true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1355,7 +1356,7 @@ class BasicEntityPersister
|
||||
|
||||
if (isset($sourceClass->associationMappings[$field])) {
|
||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
||||
$value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
|
||||
}
|
||||
|
||||
$criteria[$tableAlias . "." . $targetKeyColumn] = $value;
|
||||
|
@ -209,6 +209,11 @@ class ProxyFactory
|
||||
|
||||
$methods .= $parameterString . ')';
|
||||
$methods .= "\n" . ' {' . "\n";
|
||||
if ($this->isShortIdentifierGetter($method, $class)) {
|
||||
$methods .= ' if ($this->__isInitialized__ === false) {' . "\n";
|
||||
$methods .= ' return $this->_identifier["' . lcfirst(substr($method->getName(), 3)) . '"];' . "\n";
|
||||
$methods .= ' }' . "\n";
|
||||
}
|
||||
$methods .= ' $this->__load();' . "\n";
|
||||
$methods .= ' return parent::' . $method->getName() . '(' . $argumentString . ');';
|
||||
$methods .= "\n" . ' }' . "\n";
|
||||
@ -218,6 +223,23 @@ class ProxyFactory
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReflectionMethod $method
|
||||
* @param ClassMetadata $class
|
||||
* @return bool
|
||||
*/
|
||||
private function isShortIdentifierGetter($method, $class)
|
||||
{
|
||||
$identifier = lcfirst(substr($method->getName(), 3));
|
||||
return (
|
||||
$method->getNumberOfParameters() == 0 &&
|
||||
substr($method->getName(), 0, 3) == "get" &&
|
||||
in_array($identifier, $class->identifier, true) &&
|
||||
$class->hasField($identifier) &&
|
||||
(($method->getEndLine() - $method->getStartLine()) <= 4)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the code for the __sleep method for a proxy class.
|
||||
*
|
||||
@ -288,7 +310,7 @@ class <proxyClassName> extends \<className> implements \Doctrine\ORM\Proxy\Proxy
|
||||
unset($this->_entityPersister, $this->_identifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
<methods>
|
||||
|
||||
public function __sleep()
|
||||
|
@ -40,10 +40,12 @@ class Expr
|
||||
*
|
||||
* [php]
|
||||
* // (u.type = ?1) AND (u.role = ?2)
|
||||
* $expr->andX('u.type = ?1', 'u.role = ?2'));
|
||||
* $expr->andX($expr->eq('u.type', ':1'), $expr->eq('u.role', ':2'));
|
||||
*
|
||||
* @param mixed $x Optional clause. Defaults = null, but requires
|
||||
* at least one defined when converting to string.
|
||||
* @param Doctrine\ORM\Query\Expr\Comparison |
|
||||
* Doctrine\ORM\Query\Expr\Func |
|
||||
* Doctrine\ORM\Query\Expr\Orx
|
||||
* $x Optional clause. Defaults = null, but requires at least one defined when converting to string.
|
||||
* @return Expr\Andx
|
||||
*/
|
||||
public function andX($x = null)
|
||||
|
@ -45,12 +45,14 @@ abstract class Base
|
||||
{
|
||||
$this->addMultiple($args);
|
||||
}
|
||||
|
||||
|
||||
public function addMultiple($args = array())
|
||||
{
|
||||
foreach ((array) $args as $arg) {
|
||||
$this->add($arg);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function add($arg)
|
||||
@ -67,6 +69,8 @@ abstract class Base
|
||||
|
||||
$this->_parts[] = $arg;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function count()
|
||||
@ -79,7 +83,7 @@ abstract class Base
|
||||
if ($this->count() == 1) {
|
||||
return (string) $this->_parts[0];
|
||||
}
|
||||
|
||||
|
||||
return $this->_preSeparator . implode($this->_separator, $this->_parts) . $this->_postSeparator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1328,18 +1328,18 @@ class Parser
|
||||
// We need to check if we are in a IdentificationVariable or SingleValuedPathExpression
|
||||
$glimpse = $this->_lexer->glimpse();
|
||||
|
||||
if ($glimpse['type'] != Lexer::T_DOT) {
|
||||
$token = $this->_lexer->lookahead;
|
||||
$identVariable = $this->IdentificationVariable();
|
||||
if ($glimpse['type'] == Lexer::T_DOT) {
|
||||
return $this->SingleValuedPathExpression();
|
||||
}
|
||||
|
||||
$token = $this->_lexer->lookahead;
|
||||
$identVariable = $this->IdentificationVariable();
|
||||
|
||||
if (!isset($this->_queryComponents[$identVariable])) {
|
||||
$this->semanticalError('Cannot group by undefined identification variable.');
|
||||
}
|
||||
|
||||
return $identVariable;
|
||||
if (!isset($this->_queryComponents[$identVariable])) {
|
||||
$this->semanticalError('Cannot group by undefined identification variable.');
|
||||
}
|
||||
|
||||
return $this->SingleValuedPathExpression();
|
||||
return $identVariable;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1354,12 +1354,9 @@ class Parser
|
||||
// We need to check if we are in a ResultVariable or StateFieldPathExpression
|
||||
$glimpse = $this->_lexer->glimpse();
|
||||
|
||||
if ($glimpse['type'] != Lexer::T_DOT) {
|
||||
$token = $this->_lexer->lookahead;
|
||||
$expr = $this->ResultVariable();
|
||||
} else {
|
||||
$expr = $this->SingleValuedPathExpression();
|
||||
}
|
||||
$expr = ($glimpse['type'] != Lexer::T_DOT)
|
||||
? $this->ResultVariable()
|
||||
: $this->SingleValuedPathExpression();
|
||||
|
||||
$item = new AST\OrderByItem($expr);
|
||||
|
||||
|
@ -1126,8 +1126,9 @@ class SqlWalker implements TreeWalker
|
||||
if ( ! isset($this->_selectedClasses[$dqlAlias])) {
|
||||
$this->_selectedClasses[$dqlAlias] = $class;
|
||||
}
|
||||
|
||||
|
||||
$beginning = true;
|
||||
|
||||
// Select all fields from the queried class
|
||||
foreach ($class->fieldMappings as $fieldName => $mapping) {
|
||||
if ($partialFieldSet && !in_array($fieldName, $partialFieldSet)) {
|
||||
@ -1146,6 +1147,7 @@ class SqlWalker implements TreeWalker
|
||||
. ' AS ' . $columnAlias;
|
||||
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
|
||||
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name);
|
||||
}
|
||||
|
||||
@ -1157,6 +1159,7 @@ class SqlWalker implements TreeWalker
|
||||
foreach ($class->subClasses as $subClassName) {
|
||||
$subClass = $this->_em->getClassMetadata($subClassName);
|
||||
$sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias);
|
||||
|
||||
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
|
||||
if (isset($mapping['inherited']) || $partialFieldSet && !in_array($fieldName, $partialFieldSet)) {
|
||||
continue;
|
||||
@ -1178,8 +1181,10 @@ class SqlWalker implements TreeWalker
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE && ! isset($assoc['inherited'])) {
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
if ($beginning) $beginning = false; else $sql .= ', ';
|
||||
|
||||
$columnAlias = $this->getSQLColumnAlias($srcColumn);
|
||||
$sql .= $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
|
||||
|
||||
$this->_rsm->addMetaResult($dqlAlias, $this->_platform->getSQLResultCasing($columnAlias), $srcColumn);
|
||||
}
|
||||
}
|
||||
@ -1845,12 +1850,16 @@ class SqlWalker implements TreeWalker
|
||||
switch ($literal->type) {
|
||||
case AST\Literal::STRING:
|
||||
return $this->_conn->quote($literal->value);
|
||||
|
||||
case AST\Literal::BOOLEAN:
|
||||
$bool = strtolower($literal->value) == 'true' ? true : false;
|
||||
$boolVal = $this->_conn->getDatabasePlatform()->convertBooleans($bool);
|
||||
return is_string($boolVal) ? $this->_conn->quote($boolVal) : $boolVal;
|
||||
|
||||
return $boolVal;
|
||||
|
||||
case AST\Literal::NUMERIC:
|
||||
return $literal->value;
|
||||
|
||||
default:
|
||||
throw QueryException::invalidLiteral($literal);
|
||||
}
|
||||
|
@ -115,10 +115,12 @@ public function <methodName>()
|
||||
* <description>
|
||||
*
|
||||
* @param <variableType>$<variableName>
|
||||
* @return <entity>
|
||||
*/
|
||||
public function <methodName>(<methodTypeHint>$<variableName>)
|
||||
{
|
||||
<spaces>$this-><fieldName> = $<variableName>;
|
||||
<spaces>return $this;
|
||||
}';
|
||||
|
||||
private static $_addMethodTemplate =
|
||||
@ -150,7 +152,7 @@ public function <methodName>()
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (version_compare(\Doctrine\Common\Version::VERSION, '3.0.0-DEV', '>=')) {
|
||||
if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) {
|
||||
$this->_annotationsPrefix = 'ORM\\';
|
||||
}
|
||||
}
|
||||
@ -302,9 +304,6 @@ public function <methodName>()
|
||||
*/
|
||||
public function setAnnotationPrefix($prefix)
|
||||
{
|
||||
if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) {
|
||||
return;
|
||||
}
|
||||
$this->_annotationsPrefix = $prefix;
|
||||
}
|
||||
|
||||
@ -737,7 +736,8 @@ public function <methodName>()
|
||||
'<variableType>' => $variableType,
|
||||
'<variableName>' => Inflector::camelize($fieldName),
|
||||
'<methodName>' => $methodName,
|
||||
'<fieldName>' => $fieldName
|
||||
'<fieldName>' => $fieldName,
|
||||
'<entity>' => $this->_getClassName($metadata)
|
||||
);
|
||||
|
||||
$method = str_replace(
|
||||
@ -791,7 +791,7 @@ public function <methodName>()
|
||||
}
|
||||
|
||||
if (isset($joinColumn['onDelete'])) {
|
||||
$joinColumnAnnot[] = 'onDelete=' . ($joinColumn['onDelete'] ? 'true' : 'false');
|
||||
$joinColumnAnnot[] = 'onDelete="' . ($joinColumn['onDelete'] . '"');
|
||||
}
|
||||
|
||||
if (isset($joinColumn['columnDefinition'])) {
|
||||
|
@ -139,6 +139,9 @@ class XmlExporter extends AbstractExporter
|
||||
if (isset($field['columnName'])) {
|
||||
$idXml->addAttribute('column', $field['columnName']);
|
||||
}
|
||||
if (isset($field['associationKey']) && $field['associationKey']) {
|
||||
$idXml->addAttribute('association-key', 'true');
|
||||
}
|
||||
if ($idGeneratorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) {
|
||||
$generatorXml = $idXml->addChild('generator');
|
||||
$generatorXml->addAttribute('strategy', $idGeneratorType);
|
||||
|
@ -152,6 +152,17 @@ class SchemaValidator
|
||||
"has to be a primary key column.";
|
||||
}
|
||||
}
|
||||
|
||||
if (count($targetClass->identifier) != count($assoc['joinTable']['inverseJoinColumns'])) {
|
||||
$ce[] = "The inverse join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " .
|
||||
"have to match to ALL identifier columns of the target entity '". $targetClass->name . "'";
|
||||
}
|
||||
|
||||
if (count($class->identifier) != count($assoc['joinTable']['joinColumns'])) {
|
||||
$ce[] = "The join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " .
|
||||
"have to match to ALL identifier columns of the source entity '". $class->name . "'";
|
||||
}
|
||||
|
||||
} else if ($assoc['type'] & ClassMetadataInfo::TO_ONE) {
|
||||
foreach ($assoc['joinColumns'] AS $joinColumn) {
|
||||
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']);
|
||||
@ -167,6 +178,11 @@ class SchemaValidator
|
||||
"has to be a primary key column.";
|
||||
}
|
||||
}
|
||||
|
||||
if (count($class->identifier) != count($assoc['joinColumns'])) {
|
||||
$ce[] = "The join columns of the association '" . $assoc['fieldName'] . "' " .
|
||||
"have to match to ALL identifier columns of the source entity '". $class->name . "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,8 +215,13 @@ class UnitOfWork implements PropertyChangedListener
|
||||
* @var array
|
||||
*/
|
||||
private $orphanRemovals = array();
|
||||
|
||||
//private $_readOnlyObjects = array();
|
||||
|
||||
/**
|
||||
* Read-Only objects are never evaluated
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $readOnlyObjects = array();
|
||||
|
||||
/**
|
||||
* Map of Entity Class-Names and corresponding IDs that should eager loaded when requested.
|
||||
@ -393,6 +398,8 @@ class UnitOfWork implements PropertyChangedListener
|
||||
* If a PersistentCollection has been de-referenced in a fully MANAGED entity,
|
||||
* then this collection is marked for deletion.
|
||||
*
|
||||
* @ignore
|
||||
* @internal Don't call from the outside.
|
||||
* @param ClassMetadata $class The class descriptor of the entity.
|
||||
* @param object $entity The entity for which to compute the changes.
|
||||
*/
|
||||
@ -403,6 +410,11 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
|
||||
$oid = spl_object_hash($entity);
|
||||
|
||||
if (isset($this->readOnlyObjects[$oid])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$actualData = array();
|
||||
foreach ($class->reflFields as $name => $refProp) {
|
||||
$value = $refProp->getValue($entity);
|
||||
@ -458,7 +470,15 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$changeSet = ($isChangeTrackingNotify && isset($this->entityChangeSets[$oid])) ? $this->entityChangeSets[$oid] : array();
|
||||
|
||||
foreach ($actualData as $propName => $actualValue) {
|
||||
$orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
|
||||
if (isset($originalData[$propName])) {
|
||||
$orgValue = $originalData[$propName];
|
||||
} else if (array_key_exists($propName, $originalData)) {
|
||||
$orgValue = null;
|
||||
} else {
|
||||
// skip field, its a partially omitted one!
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($class->associationMappings[$propName])) {
|
||||
$assoc = $class->associationMappings[$propName];
|
||||
if ($assoc['type'] & ClassMetadata::TO_ONE && $orgValue !== $actualValue) {
|
||||
@ -470,8 +490,9 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
} else if ($orgValue instanceof PersistentCollection && $orgValue !== $actualValue) {
|
||||
// A PersistentCollection was de-referenced, so delete it.
|
||||
if ( ! in_array($orgValue, $this->collectionDeletions, true)) {
|
||||
$this->collectionDeletions[] = $orgValue;
|
||||
$coid = spl_object_hash($orgValue);
|
||||
if ( ! isset($this->collectionDeletions[$coid]) ) {
|
||||
$this->collectionDeletions[$coid] = $orgValue;
|
||||
$changeSet[$propName] = $orgValue; // Signal changeset, to-many assocs will be ignored.
|
||||
}
|
||||
}
|
||||
@ -528,7 +549,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
|
||||
foreach ($entitiesToProcess as $entity) {
|
||||
// Ignore uninitialized proxy objects
|
||||
if (/* $entity is readOnly || */ $entity instanceof Proxy && ! $entity->__isInitialized__) {
|
||||
if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
|
||||
continue;
|
||||
}
|
||||
// Only MANAGED entities that are NOT SCHEDULED FOR INSERTION are processed here.
|
||||
@ -549,10 +570,11 @@ class UnitOfWork implements PropertyChangedListener
|
||||
private function computeAssociationChanges($assoc, $value)
|
||||
{
|
||||
if ($value instanceof PersistentCollection && $value->isDirty()) {
|
||||
$coid = spl_object_hash($value);
|
||||
if ($assoc['isOwningSide']) {
|
||||
$this->collectionUpdates[] = $value;
|
||||
$this->collectionUpdates[$coid] = $value;
|
||||
}
|
||||
$this->visitedCollections[] = $value;
|
||||
$this->visitedCollections[$coid] = $value;
|
||||
}
|
||||
|
||||
// Look through the entities, and in any of their associations, for transient (new)
|
||||
@ -635,7 +657,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
* @param object $entity The entity for which to (re)calculate the change set.
|
||||
* @throws InvalidArgumentException If the passed entity is not MANAGED.
|
||||
*/
|
||||
public function recomputeSingleEntityChangeSet($class, $entity)
|
||||
public function recomputeSingleEntityChangeSet(ClassMetadata $class, $entity)
|
||||
{
|
||||
$oid = spl_object_hash($entity);
|
||||
|
||||
@ -853,6 +875,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||
if ( ! $calc->hasClass($targetClass->name)) {
|
||||
$calc->addClass($targetClass);
|
||||
$newNodes[] = $targetClass;
|
||||
}
|
||||
$calc->addDependency($targetClass, $class);
|
||||
// If the target class has mapped subclasses,
|
||||
@ -1452,11 +1475,17 @@ class UnitOfWork implements PropertyChangedListener
|
||||
if ($this->getEntityState($other, self::STATE_DETACHED) == self::STATE_MANAGED) {
|
||||
$prop->setValue($managedCopy, $other);
|
||||
} else {
|
||||
|
||||
$targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
|
||||
$id = $targetClass->getIdentifierValues($other);
|
||||
$proxy = $this->em->getProxyFactory()->getProxy($assoc2['targetEntity'], $id);
|
||||
$prop->setValue($managedCopy, $proxy);
|
||||
$this->registerManaged($proxy, $id, array());
|
||||
$relatedId = $targetClass->getIdentifierValues($other);
|
||||
|
||||
if ($targetClass->subClasses) {
|
||||
$entity = $this->em->find($targetClass->name, $relatedId);
|
||||
} else {
|
||||
$proxy = $this->em->getProxyFactory()->getProxy($assoc2['targetEntity'], $relatedId);
|
||||
$prop->setValue($managedCopy, $proxy);
|
||||
$this->registerManaged($proxy, $relatedId, array());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1538,8 +1567,9 @@ class UnitOfWork implements PropertyChangedListener
|
||||
*
|
||||
* @param object $entity
|
||||
* @param array $visited
|
||||
* @param boolean $noCascade if true, don't cascade detach operation
|
||||
*/
|
||||
private function doDetach($entity, array &$visited)
|
||||
private function doDetach($entity, array &$visited, $noCascade = false)
|
||||
{
|
||||
$oid = spl_object_hash($entity);
|
||||
if (isset($visited[$oid])) {
|
||||
@ -1561,8 +1591,10 @@ class UnitOfWork implements PropertyChangedListener
|
||||
case self::STATE_DETACHED:
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cascadeDetach($entity, $visited);
|
||||
|
||||
if (!$noCascade) {
|
||||
$this->cascadeDetach($entity, $visited);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1813,28 +1845,41 @@ class UnitOfWork implements PropertyChangedListener
|
||||
|
||||
/**
|
||||
* Clears the UnitOfWork.
|
||||
*
|
||||
* @param string $entityName if given, only entities of this type will get detached
|
||||
*/
|
||||
public function clear()
|
||||
public function clear($entityName = null)
|
||||
{
|
||||
$this->identityMap =
|
||||
$this->entityIdentifiers =
|
||||
$this->originalEntityData =
|
||||
$this->entityChangeSets =
|
||||
$this->entityStates =
|
||||
$this->scheduledForDirtyCheck =
|
||||
$this->entityInsertions =
|
||||
$this->entityUpdates =
|
||||
$this->entityDeletions =
|
||||
$this->collectionDeletions =
|
||||
$this->collectionUpdates =
|
||||
$this->extraUpdates =
|
||||
$this->orphanRemovals = array();
|
||||
if ($this->commitOrderCalculator !== null) {
|
||||
$this->commitOrderCalculator->clear();
|
||||
if ($entityName === null) {
|
||||
$this->identityMap =
|
||||
$this->entityIdentifiers =
|
||||
$this->originalEntityData =
|
||||
$this->entityChangeSets =
|
||||
$this->entityStates =
|
||||
$this->scheduledForDirtyCheck =
|
||||
$this->entityInsertions =
|
||||
$this->entityUpdates =
|
||||
$this->entityDeletions =
|
||||
$this->collectionDeletions =
|
||||
$this->collectionUpdates =
|
||||
$this->extraUpdates =
|
||||
$this->orphanRemovals = array();
|
||||
if ($this->commitOrderCalculator !== null) {
|
||||
$this->commitOrderCalculator->clear();
|
||||
}
|
||||
} else {
|
||||
$visited = array();
|
||||
foreach ($this->identityMap as $className => $entities) {
|
||||
if ($className === $entityName) {
|
||||
foreach ($entities as $entity) {
|
||||
$this->doDetach($entity, $visited, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->evm->hasListeners(Events::onClear)) {
|
||||
$this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em));
|
||||
$this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->em, $entityName));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1862,12 +1907,12 @@ class UnitOfWork implements PropertyChangedListener
|
||||
{
|
||||
//TODO: if $coll is already scheduled for recreation ... what to do?
|
||||
// Just remove $coll from the scheduled recreations?
|
||||
$this->collectionDeletions[] = $coll;
|
||||
$this->collectionDeletions[spl_object_hash($coll)] = $coll;
|
||||
}
|
||||
|
||||
public function isCollectionScheduledForDeletion(PersistentCollection $coll)
|
||||
{
|
||||
return in_array($coll, $this->collectionsDeletions, true);
|
||||
return isset( $this->collectionsDeletions[spl_object_hash($coll)] );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2407,4 +2452,37 @@ class UnitOfWork implements PropertyChangedListener
|
||||
{
|
||||
return method_exists($obj, '__toString') ? (string)$obj : get_class($obj).'@'.spl_object_hash($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks an entity as read-only so that it will not be considered for updates during UnitOfWork#commit().
|
||||
*
|
||||
* This operation cannot be undone as some parts of the UnitOfWork now keep gathering information
|
||||
* on this object that might be necessary to perform a correct udpate.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @param $object
|
||||
* @return void
|
||||
*/
|
||||
public function markReadOnly($object)
|
||||
{
|
||||
if ( ! is_object($object) || ! $this->isInIdentityMap($object)) {
|
||||
throw new InvalidArgumentException("Managed entity required");
|
||||
}
|
||||
$this->readOnlyObjects[spl_object_hash($object)] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this entity read only?
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @param $object
|
||||
* @return void
|
||||
*/
|
||||
public function isReadOnly($object)
|
||||
{
|
||||
if ( ! is_object($object) ) {
|
||||
throw new InvalidArgumentException("Managed entity required");
|
||||
}
|
||||
return isset($this->readOnlyObjects[spl_object_hash($object)]);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class CmsUser
|
||||
*/
|
||||
public $id;
|
||||
/**
|
||||
* @Column(type="string", length=50)
|
||||
* @Column(type="string", length=50, nullable=true)
|
||||
*/
|
||||
public $status;
|
||||
/**
|
||||
@ -35,7 +35,7 @@ class CmsUser
|
||||
*/
|
||||
public $phonenumbers;
|
||||
/**
|
||||
* @OneToMany(targetEntity="CmsArticle", mappedBy="user")
|
||||
* @OneToMany(targetEntity="CmsArticle", mappedBy="user", cascade={"detach"})
|
||||
*/
|
||||
public $articles;
|
||||
/**
|
||||
@ -48,7 +48,7 @@ class CmsUser
|
||||
*/
|
||||
public $email;
|
||||
/**
|
||||
* @ManyToMany(targetEntity="CmsGroup", inversedBy="users", cascade={"persist", "merge"})
|
||||
* @ManyToMany(targetEntity="CmsGroup", inversedBy="users", cascade={"persist", "merge", "detach"})
|
||||
* @JoinTable(name="cms_users_groups",
|
||||
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}
|
||||
|
@ -7,7 +7,11 @@ namespace Doctrine\Tests\Models\Company;
|
||||
* @Table(name="company_contracts")
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"fix" = "CompanyFixContract", "flexible" = "CompanyFlexContract", "flexultra" = "CompanyFlexUltraContract"})
|
||||
* @DiscriminatorMap({
|
||||
* "fix" = "CompanyFixContract",
|
||||
* "flexible" = "CompanyFlexContract",
|
||||
* "flexultra" = "CompanyFlexUltraContract"
|
||||
* })
|
||||
*/
|
||||
abstract class CompanyContract
|
||||
{
|
||||
|
91
tests/Doctrine/Tests/ORM/Event/EntityEventDelegateeTest.php
Normal file
91
tests/Doctrine/Tests/ORM/Event/EntityEventDelegateeTest.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Event;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* @group DDC-1415
|
||||
*/
|
||||
class EntityEventDelegatorTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\Event\EntityEventDelegator
|
||||
*/
|
||||
private $delegator;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->delegator = new \Doctrine\ORM\Event\EntityEventDelegator();
|
||||
}
|
||||
|
||||
public function testGetSubscribedEventsWhenEmpty()
|
||||
{
|
||||
$this->assertEquals(array(), $this->delegator->getSubscribedEvents());
|
||||
}
|
||||
|
||||
public function testAddListener()
|
||||
{
|
||||
$this->delegator->addEventListener('postLoad', 'stdClass', new DelegateeEventListener());
|
||||
$this->assertEquals(array('postLoad'), $this->delegator->getSubscribedEvents());
|
||||
}
|
||||
|
||||
public function testAddSubscriber()
|
||||
{
|
||||
$this->delegator->addEventSubscriber(new DelegateeEventListener(), 'stdClass');
|
||||
$this->assertEquals(array('postLoad'), $this->delegator->getSubscribedEvents());
|
||||
}
|
||||
|
||||
public function testAddListenerAfterFrozenThrowsException()
|
||||
{
|
||||
$this->delegator->getSubscribedEvents(); // freezes
|
||||
|
||||
$this->setExpectedException("LogicException", "Cannot add event listeners aft");
|
||||
$this->delegator->addEventListener('postLoad', 'stdClass', new DelegateeEventListener());
|
||||
}
|
||||
|
||||
public function testDelegateEvent()
|
||||
{
|
||||
$delegatee = new DelegateeEventListener();
|
||||
$this->delegator->addEventListener('postLoad', 'stdClass', $delegatee);
|
||||
|
||||
$event = new \Doctrine\ORM\Event\LifecycleEventArgs(new \stdClass(), $this->_getTestEntityManager());
|
||||
$this->delegator->postLoad($event);
|
||||
$this->delegator->postLoad($event);
|
||||
|
||||
$this->assertEquals(2, $delegatee->postLoad);
|
||||
}
|
||||
|
||||
public function testDelegatePickEntity()
|
||||
{
|
||||
$delegatee = new DelegateeEventListener();
|
||||
$this->delegator->addEventListener('postLoad', 'stdClass', $delegatee);
|
||||
|
||||
$event1 = new \Doctrine\ORM\Event\LifecycleEventArgs(new \stdClass(), $this->_getTestEntityManager());
|
||||
$event2 = new \Doctrine\ORM\Event\LifecycleEventArgs(new \Doctrine\Tests\Models\CMS\CmsUser(), $this->_getTestEntityManager());
|
||||
$this->delegator->postLoad($event1);
|
||||
$this->delegator->postLoad($event2);
|
||||
|
||||
$this->assertEquals(1, $delegatee->postLoad);
|
||||
}
|
||||
}
|
||||
|
||||
class DelegateeEventListener implements \Doctrine\Common\EventSubscriber
|
||||
{
|
||||
public $postLoad = 0;
|
||||
|
||||
public function postLoad($args)
|
||||
{
|
||||
$this->postLoad++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of events this subscriber wants to listen to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getSubscribedEvents()
|
||||
{
|
||||
return array('postLoad');
|
||||
}
|
||||
}
|
@ -863,7 +863,6 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
public function testGetPartialReferenceToUpdateObjectWithoutLoadingIt()
|
||||
{
|
||||
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
|
||||
$user = new CmsUser();
|
||||
$user->username = "beberlei";
|
||||
$user->name = "Benjamin E.";
|
||||
@ -882,7 +881,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$this->assertEquals('Stephan', $this->_em->find(get_class($user), $userId)->name);
|
||||
$this->assertEquals('Benjamin E.', $this->_em->find(get_class($user), $userId)->name);
|
||||
}
|
||||
|
||||
public function testMergePersistsNewEntities()
|
||||
@ -981,4 +980,54 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertTrue($article->user->__isInitialized__, "...but its initialized!");
|
||||
$this->assertEquals($qc+2, $this->getCurrentQueryCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1278
|
||||
*/
|
||||
public function testClearWithEntityName()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Dominik';
|
||||
$user->username = 'domnikl';
|
||||
$user->status = 'developer';
|
||||
|
||||
$address = new CmsAddress();
|
||||
$address->city = "Springfield";
|
||||
$address->zip = "12354";
|
||||
$address->country = "Germany";
|
||||
$address->street = "Foo Street";
|
||||
$address->user = $user;
|
||||
$user->address = $address;
|
||||
|
||||
$article1 = new CmsArticle();
|
||||
$article1->topic = 'Foo';
|
||||
$article1->text = 'Foo Text';
|
||||
|
||||
$article2 = new CmsArticle();
|
||||
$article2->topic = 'Bar';
|
||||
$article2->text = 'Bar Text';
|
||||
|
||||
$user->addArticle($article1);
|
||||
$user->addArticle($article2);
|
||||
|
||||
$this->_em->persist($article1);
|
||||
$this->_em->persist($article2);
|
||||
$this->_em->persist($address);
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$unitOfWork = $this->_em->getUnitOfWork();
|
||||
|
||||
$this->_em->clear('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_DETACHED, $unitOfWork->getEntityState($user));
|
||||
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $unitOfWork->getEntityState($address));
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $unitOfWork->getEntityState($article1));
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_MANAGED, $unitOfWork->getEntityState($article2));
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$this->assertEquals(\Doctrine\ORM\UnitOfWork::STATE_DETACHED, $unitOfWork->getEntityState($address));
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,30 @@ class DefaultValuesTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals($userId, $a2->getUser()->getId());
|
||||
$this->assertEquals('Poweruser', $a2->getUser()->type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-1386
|
||||
*/
|
||||
public function testGetPartialReferenceWithDefaultValueNotEvalutedInFlush()
|
||||
{
|
||||
$user = new DefaultValueUser;
|
||||
$user->name = 'romanb';
|
||||
$user->type = 'Normaluser';
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$user = $this->_em->getPartialReference('Doctrine\Tests\ORM\Functional\DefaultValueUser', $user->id);
|
||||
$this->assertTrue($this->_em->getUnitOfWork()->isReadOnly($user));
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$user = $this->_em->find('Doctrine\Tests\ORM\Functional\DefaultValueUser', $user->id);
|
||||
|
||||
$this->assertEquals('Normaluser', $user->type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,18 +38,25 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$user2->status = 'dev';
|
||||
$this->_em->persist($user2);
|
||||
|
||||
$user3 = new CmsUser;
|
||||
$user3->name = 'Benjamin';
|
||||
$user3->username = 'beberlei';
|
||||
$user3->status = null;
|
||||
$this->_em->persist($user3);
|
||||
|
||||
$this->_em->flush();
|
||||
|
||||
|
||||
$user1Id = $user->getId();
|
||||
|
||||
|
||||
unset($user);
|
||||
unset($user2);
|
||||
|
||||
unset($user3);
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
return $user1Id;
|
||||
}
|
||||
|
||||
|
||||
public function loadAssociatedFixture()
|
||||
{
|
||||
$address = new CmsAddress();
|
||||
@ -189,7 +196,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$users = $repos->findAll();
|
||||
$this->assertEquals(2, count($users));
|
||||
$this->assertEquals(3, count($users));
|
||||
}
|
||||
|
||||
public function testFindByAlias()
|
||||
@ -202,7 +209,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$repos = $this->_em->getRepository('CMS:CmsUser');
|
||||
|
||||
$users = $repos->findAll();
|
||||
$this->assertEquals(2, count($users));
|
||||
$this->assertEquals(3, count($users));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -284,10 +291,11 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testFindMagicCallByNullValue()
|
||||
{
|
||||
$this->loadFixture();
|
||||
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$this->setExpectedException('Doctrine\ORM\ORMException');
|
||||
$users = $repos->findByStatus(null);
|
||||
$this->assertEquals(1, count($users));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -389,7 +397,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
/**
|
||||
* @group DDC-1087
|
||||
*/
|
||||
public function testIsNullCriteria()
|
||||
public function testIsNullCriteriaDoesNotGenerateAParameter()
|
||||
{
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
$users = $repos->findBy(array('status' => null, 'username' => 'romanb'));
|
||||
@ -399,6 +407,16 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals(array('romanb'), $params);
|
||||
}
|
||||
|
||||
public function testIsNullCriteria()
|
||||
{
|
||||
$this->loadFixture();
|
||||
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$users = $repos->findBy(array('status' => null));
|
||||
$this->assertEquals(1, count($users));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1094
|
||||
*/
|
||||
@ -411,7 +429,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$users1 = $repos->findBy(array(), null, 1, 0);
|
||||
$users2 = $repos->findBy(array(), null, 1, 1);
|
||||
|
||||
$this->assertEquals(2, count($repos->findBy(array())));
|
||||
$this->assertEquals(3, count($repos->findBy(array())));
|
||||
$this->assertEquals(1, count($users1));
|
||||
$this->assertEquals(1, count($users2));
|
||||
$this->assertNotSame($users1[0], $users2[0]);
|
||||
@ -428,10 +446,10 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$usersAsc = $repos->findBy(array(), array("username" => "ASC"));
|
||||
$usersDesc = $repos->findBy(array(), array("username" => "DESC"));
|
||||
|
||||
$this->assertEquals(2, count($usersAsc), "Pre-condition: only two users in fixture");
|
||||
$this->assertEquals(2, count($usersDesc), "Pre-condition: only two users in fixture");
|
||||
$this->assertSame($usersAsc[0], $usersDesc[1]);
|
||||
$this->assertSame($usersAsc[1], $usersDesc[0]);
|
||||
$this->assertEquals(3, count($usersAsc), "Pre-condition: only three users in fixture");
|
||||
$this->assertEquals(3, count($usersDesc), "Pre-condition: only three users in fixture");
|
||||
$this->assertSame($usersAsc[0], $usersDesc[2]);
|
||||
$this->assertSame($usersAsc[2], $usersDesc[0]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -78,7 +78,7 @@ class LifecycleCallbackTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$reference = $this->_em->getReference('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity', $id);
|
||||
$this->assertFalse($reference->postLoadCallbackInvoked);
|
||||
|
||||
$reference->getId(); // trigger proxy load
|
||||
$reference->getValue(); // trigger proxy load
|
||||
$this->assertTrue($reference->postLoadCallbackInvoked);
|
||||
}
|
||||
|
||||
@ -210,6 +210,10 @@ class LifecycleCallbackTestEntity
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getValue() {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/** @PrePersist */
|
||||
public function doStuffOnPrePersist() {
|
||||
$this->prePersistCallbackInvoked = true;
|
||||
@ -274,4 +278,4 @@ class LifecycleListenerPreUpdate
|
||||
{
|
||||
$eventArgs->setNewValue('name', 'Bob');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,4 +147,28 @@ class ReferenceProxyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->assertTrue($entity->wakeUp, "Loading the proxy should call __wakeup().");
|
||||
}
|
||||
|
||||
public function testDoNotInitializeProxyOnGettingTheIdentifier()
|
||||
{
|
||||
$id = $this->createProduct();
|
||||
|
||||
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
|
||||
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
|
||||
|
||||
$this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy.");
|
||||
$this->assertEquals($id, $entity->getId());
|
||||
$this->assertFalse($entity->__isInitialized__, "Getting the identifier doesn't initialize the proxy.");
|
||||
}
|
||||
|
||||
public function testInitializeProxyOnGettingSomethingOtherThanTheIdentifier()
|
||||
{
|
||||
$id = $this->createProduct();
|
||||
|
||||
/* @var $entity Doctrine\Tests\Models\ECommerce\ECommerceProduct */
|
||||
$entity = $this->_em->getReference('Doctrine\Tests\Models\ECommerce\ECommerceProduct' , $id);
|
||||
|
||||
$this->assertFalse($entity->__isInitialized__, "Pre-Condition: Object is unitialized proxy.");
|
||||
$this->assertEquals('Doctrine Cookbook', $entity->getName());
|
||||
$this->assertTrue($entity->__isInitialized__, "Getting something other than the identifier initializes the proxy.");
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,8 @@ class DDC1238Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
// force proxy load, getId() doesn't work anymore
|
||||
$user->getName();
|
||||
$userId = $user->getId();
|
||||
$this->_em->clear();
|
||||
|
||||
@ -60,6 +62,8 @@ class DDC1238Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$user2 = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
|
||||
|
||||
// force proxy load, getId() doesn't work anymore
|
||||
$user->getName();
|
||||
$this->assertNull($user->getId(), "Now this is null, we already have a user instance of that type");
|
||||
}
|
||||
}
|
||||
|
99
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1383Test.php
Normal file
99
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1383Test.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-1383
|
||||
*/
|
||||
class DDC1383Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1383AbstractEntity'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1383Entity'),
|
||||
));
|
||||
} catch(\Exception $ignored) {}
|
||||
}
|
||||
|
||||
public function testFailingCase()
|
||||
{
|
||||
$parent = new DDC1383Entity();
|
||||
$child = new DDC1383Entity();
|
||||
|
||||
$child->setReference($parent);
|
||||
|
||||
$this->_em->persist($parent);
|
||||
$this->_em->persist($child);
|
||||
|
||||
$id = $child->getId();
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
// Try merging the parent entity
|
||||
$child = $this->_em->merge($child);
|
||||
$parent = $child->getReference();
|
||||
|
||||
// Parent is not instance of the abstract class
|
||||
self::assertTrue($parent instanceof DDC1383AbstractEntity,
|
||||
"Entity class is " . get_class($parent) . ', "DDC1383AbstractEntity" was expected');
|
||||
|
||||
// Parent is NOT instance of entity
|
||||
self::assertTrue($parent instanceof DDC1383Entity,
|
||||
"Entity class is " . get_class($parent) . ', "DDC1383Entity" was expected');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("JOINED")
|
||||
* @DiscriminatorColumn(name="discr", type="integer")
|
||||
* @DiscriminatorMap({1 = "DDC1383Entity"})
|
||||
*/
|
||||
abstract class DDC1383AbstractEntity
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1383Entity extends DDC1383AbstractEntity
|
||||
{
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC1383AbstractEntity")
|
||||
*/
|
||||
protected $reference;
|
||||
|
||||
public function getReference()
|
||||
{
|
||||
return $this->reference;
|
||||
}
|
||||
|
||||
public function setReference(DDC1383AbstractEntity $reference)
|
||||
{
|
||||
$this->reference = $reference;
|
||||
}
|
||||
}
|
@ -31,8 +31,8 @@ class DDC381Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$entity = $this->_em->getReference('Doctrine\Tests\ORM\Functional\Ticket\DDC381Entity', $persistedId);
|
||||
|
||||
// explicitly load proxy
|
||||
$id = $entity->getId();
|
||||
// explicitly load proxy (getId() does not trigger reload of proxy)
|
||||
$id = $entity->getOtherMethod();
|
||||
|
||||
$data = serialize($entity);
|
||||
$entity = unserialize($data);
|
||||
@ -55,4 +55,9 @@ class DDC381Entity
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getOtherMethod()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -37,6 +37,10 @@ class TypeTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals(0.1515, $decimal->highScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1394
|
||||
* @return void
|
||||
*/
|
||||
public function testBoolean()
|
||||
{
|
||||
$bool = new BooleanModel();
|
||||
@ -46,7 +50,7 @@ class TypeTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$dql = "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b";
|
||||
$dql = "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = true";
|
||||
$bool = $this->_em->createQuery($dql)->getSingleResult();
|
||||
|
||||
$this->assertTrue($bool->booleanField);
|
||||
@ -56,7 +60,7 @@ class TypeTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$dql = "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b";
|
||||
$dql = "SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = false";
|
||||
$bool = $this->_em->createQuery($dql)->getSingleResult();
|
||||
|
||||
$this->assertFalse($bool->booleanField);
|
||||
|
@ -763,4 +763,58 @@ class ArrayHydratorTest extends HydrationTestCase
|
||||
|
||||
$this->assertEquals(1, count($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1358
|
||||
*/
|
||||
public function testMissingIdForRootEntity()
|
||||
{
|
||||
$rsm = new ResultSetMapping;
|
||||
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
|
||||
$rsm->addFieldResult('u', 'u__id', 'id');
|
||||
$rsm->addFieldResult('u', 'u__status', 'status');
|
||||
$rsm->addScalarResult('sclr0', 'nameUpper');
|
||||
|
||||
// Faked result set
|
||||
$resultSet = array(
|
||||
//row1
|
||||
array(
|
||||
'u__id' => '1',
|
||||
'u__status' => 'developer',
|
||||
'sclr0' => 'ROMANB',
|
||||
),
|
||||
array(
|
||||
'u__id' => null,
|
||||
'u__status' => null,
|
||||
'sclr0' => 'ROMANB',
|
||||
),
|
||||
array(
|
||||
'u__id' => '2',
|
||||
'u__status' => 'developer',
|
||||
'sclr0' => 'JWAGE',
|
||||
),
|
||||
array(
|
||||
'u__id' => null,
|
||||
'u__status' => null,
|
||||
'sclr0' => 'JWAGE',
|
||||
),
|
||||
);
|
||||
|
||||
$stmt = new HydratorMockStatement($resultSet);
|
||||
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
|
||||
|
||||
$result = $hydrator->hydrateAll($stmt, $rsm);
|
||||
|
||||
$this->assertEquals(4, count($result), "Should hydrate four results.");
|
||||
|
||||
$this->assertEquals('ROMANB', $result[0]['nameUpper']);
|
||||
$this->assertEquals('ROMANB', $result[1]['nameUpper']);
|
||||
$this->assertEquals('JWAGE', $result[2]['nameUpper']);
|
||||
$this->assertEquals('JWAGE', $result[3]['nameUpper']);
|
||||
|
||||
$this->assertEquals(array('id' => 1, 'status' => 'developer'), $result[0][0]);
|
||||
$this->assertNull($result[1][0]);
|
||||
$this->assertEquals(array('id' => 2, 'status' => 'developer'), $result[2][0]);
|
||||
$this->assertNull($result[3][0]);
|
||||
}
|
||||
}
|
@ -1008,4 +1008,165 @@ class ObjectHydratorTest extends HydrationTestCase
|
||||
$this->assertEquals(4, count($result[1]->groups));
|
||||
$this->assertEquals(2, count($result[1]->phonenumbers));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1358
|
||||
*/
|
||||
public function testMissingIdForRootEntity()
|
||||
{
|
||||
$rsm = new ResultSetMapping;
|
||||
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
|
||||
$rsm->addFieldResult('u', 'u__id', 'id');
|
||||
$rsm->addFieldResult('u', 'u__status', 'status');
|
||||
$rsm->addScalarResult('sclr0', 'nameUpper');
|
||||
|
||||
// Faked result set
|
||||
$resultSet = array(
|
||||
//row1
|
||||
array(
|
||||
'u__id' => '1',
|
||||
'u__status' => 'developer',
|
||||
'sclr0' => 'ROMANB',
|
||||
),
|
||||
array(
|
||||
'u__id' => null,
|
||||
'u__status' => null,
|
||||
'sclr0' => 'ROMANB',
|
||||
),
|
||||
array(
|
||||
'u__id' => '2',
|
||||
'u__status' => 'developer',
|
||||
'sclr0' => 'JWAGE',
|
||||
),
|
||||
array(
|
||||
'u__id' => null,
|
||||
'u__status' => null,
|
||||
'sclr0' => 'JWAGE',
|
||||
),
|
||||
);
|
||||
|
||||
$stmt = new HydratorMockStatement($resultSet);
|
||||
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
|
||||
|
||||
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
|
||||
|
||||
$this->assertEquals(4, count($result), "Should hydrate four results.");
|
||||
|
||||
$this->assertEquals('ROMANB', $result[0]['nameUpper']);
|
||||
$this->assertEquals('ROMANB', $result[1]['nameUpper']);
|
||||
$this->assertEquals('JWAGE', $result[2]['nameUpper']);
|
||||
$this->assertEquals('JWAGE', $result[3]['nameUpper']);
|
||||
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[0][0]);
|
||||
$this->assertNull($result[1][0]);
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $result[2][0]);
|
||||
$this->assertNull($result[3][0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1358
|
||||
* @return void
|
||||
*/
|
||||
public function testMissingIdForCollectionValuedChildEntity()
|
||||
{
|
||||
$rsm = new ResultSetMapping;
|
||||
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
|
||||
$rsm->addJoinedEntityResult(
|
||||
'Doctrine\Tests\Models\CMS\CmsPhonenumber',
|
||||
'p',
|
||||
'u',
|
||||
'phonenumbers'
|
||||
);
|
||||
$rsm->addFieldResult('u', 'u__id', 'id');
|
||||
$rsm->addFieldResult('u', 'u__status', 'status');
|
||||
$rsm->addScalarResult('sclr0', 'nameUpper');
|
||||
$rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
|
||||
|
||||
// Faked result set
|
||||
$resultSet = array(
|
||||
//row1
|
||||
array(
|
||||
'u__id' => '1',
|
||||
'u__status' => 'developer',
|
||||
'sclr0' => 'ROMANB',
|
||||
'p__phonenumber' => '42',
|
||||
),
|
||||
array(
|
||||
'u__id' => '1',
|
||||
'u__status' => 'developer',
|
||||
'sclr0' => 'ROMANB',
|
||||
'p__phonenumber' => null
|
||||
),
|
||||
array(
|
||||
'u__id' => '2',
|
||||
'u__status' => 'developer',
|
||||
'sclr0' => 'JWAGE',
|
||||
'p__phonenumber' => '91'
|
||||
),
|
||||
array(
|
||||
'u__id' => '2',
|
||||
'u__status' => 'developer',
|
||||
'sclr0' => 'JWAGE',
|
||||
'p__phonenumber' => null
|
||||
)
|
||||
);
|
||||
|
||||
$stmt = new HydratorMockStatement($resultSet);
|
||||
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
|
||||
|
||||
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals(1, $result[0][0]->phonenumbers->count());
|
||||
$this->assertEquals(1, $result[1][0]->phonenumbers->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1358
|
||||
*/
|
||||
public function testMissingIdForSingleValuedChildEntity()
|
||||
{
|
||||
$rsm = new ResultSetMapping;
|
||||
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
|
||||
$rsm->addJoinedEntityResult(
|
||||
'Doctrine\Tests\Models\CMS\CmsAddress',
|
||||
'a',
|
||||
'u',
|
||||
'address'
|
||||
);
|
||||
$rsm->addFieldResult('u', 'u__id', 'id');
|
||||
$rsm->addFieldResult('u', 'u__status', 'status');
|
||||
$rsm->addScalarResult('sclr0', 'nameUpper');
|
||||
$rsm->addFieldResult('a', 'a__id', 'id');
|
||||
$rsm->addFieldResult('a', 'a__city', 'city');
|
||||
$rsm->addMetaResult('a', 'user_id', 'user_id');
|
||||
|
||||
// Faked result set
|
||||
$resultSet = array(
|
||||
//row1
|
||||
array(
|
||||
'u__id' => '1',
|
||||
'u__status' => 'developer',
|
||||
'sclr0' => 'ROMANB',
|
||||
'a__id' => 1,
|
||||
'a__city' => 'Berlin',
|
||||
),
|
||||
array(
|
||||
'u__id' => '2',
|
||||
'u__status' => 'developer',
|
||||
'sclr0' => 'BENJAMIN',
|
||||
'a__id' => null,
|
||||
'a__city' => null,
|
||||
),
|
||||
);
|
||||
|
||||
$stmt = new HydratorMockStatement($resultSet);
|
||||
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
|
||||
|
||||
$result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress', $result[0][0]->address);
|
||||
$this->assertNull($result[1][0]->address);
|
||||
}
|
||||
}
|
||||
|
113
tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php
Normal file
113
tests/Doctrine/Tests/ORM/Mapping/Symfony/AbstractDriverTest.php
Normal 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\Tests\ORM\Mapping\Symfony;
|
||||
|
||||
/**
|
||||
* @group DDC-1418
|
||||
*/
|
||||
abstract class AbstractDriverTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testFindMappingFile()
|
||||
{
|
||||
$driver = $this->getDriver(array(
|
||||
'MyNamespace\MySubnamespace\EntityFoo' => 'foo',
|
||||
'MyNamespace\MySubnamespace\Entity' => $this->dir,
|
||||
));
|
||||
|
||||
touch($filename = $this->dir.'/Foo'.$this->getFileExtension());
|
||||
$this->assertEquals($filename, $this->invoke($driver, '_findMappingFile', array('MyNamespace\MySubnamespace\Entity\Foo')));
|
||||
}
|
||||
|
||||
public function testFindMappingFileInSubnamespace()
|
||||
{
|
||||
$driver = $this->getDriver(array(
|
||||
'MyNamespace\MySubnamespace\Entity' => $this->dir,
|
||||
));
|
||||
|
||||
touch($filename = $this->dir.'/Foo.Bar'.$this->getFileExtension());
|
||||
$this->assertEquals($filename, $this->invoke($driver, '_findMappingFile', array('MyNamespace\MySubnamespace\Entity\Foo\Bar')));
|
||||
}
|
||||
|
||||
public function testFindMappingFileNamespacedFoundFileNotFound()
|
||||
{
|
||||
$this->setExpectedException(
|
||||
'Doctrine\ORM\Mapping\MappingException',
|
||||
"No mapping file found named '".$this->dir."/Foo".$this->getFileExtension()."' for class 'MyNamespace\MySubnamespace\Entity\Foo'."
|
||||
);
|
||||
|
||||
$driver = $this->getDriver(array(
|
||||
'MyNamespace\MySubnamespace\Entity' => $this->dir,
|
||||
));
|
||||
|
||||
$this->invoke($driver, '_findMappingFile', array('MyNamespace\MySubnamespace\Entity\Foo'));
|
||||
}
|
||||
|
||||
public function testFindMappingNamespaceNotFound()
|
||||
{
|
||||
$this->setExpectedException(
|
||||
'Doctrine\ORM\Mapping\MappingException',
|
||||
"No mapping file found named 'Foo".$this->getFileExtension()."' for class 'MyOtherNamespace\MySubnamespace\Entity\Foo'."
|
||||
);
|
||||
|
||||
$driver = $this->getDriver(array(
|
||||
'MyNamespace\MySubnamespace\Entity' => $this->dir,
|
||||
));
|
||||
|
||||
$this->invoke($driver, '_findMappingFile', array('MyOtherNamespace\MySubnamespace\Entity\Foo'));
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->dir = sys_get_temp_dir().'/abstract_driver_test';
|
||||
@mkdir($this->dir, 0777, true);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->dir), \RecursiveIteratorIterator::CHILD_FIRST);
|
||||
|
||||
foreach ($iterator as $path) {
|
||||
if ($path->isDir()) {
|
||||
@rmdir($path);
|
||||
} else {
|
||||
@unlink($path);
|
||||
}
|
||||
}
|
||||
|
||||
@rmdir($this->dir);
|
||||
}
|
||||
|
||||
abstract protected function getFileExtension();
|
||||
abstract protected function getDriver(array $paths = array());
|
||||
|
||||
private function setField($obj, $field, $value)
|
||||
{
|
||||
$ref = new \ReflectionProperty($obj, $field);
|
||||
$ref->setAccessible(true);
|
||||
$ref->setValue($obj, $value);
|
||||
}
|
||||
|
||||
private function invoke($obj, $method, array $args = array()) {
|
||||
$ref = new \ReflectionMethod($obj, $method);
|
||||
$ref->setAccessible(true);
|
||||
|
||||
return $ref->invokeArgs($obj, $args);
|
||||
}
|
||||
}
|
40
tests/Doctrine/Tests/ORM/Mapping/Symfony/XmlDriverTest.php
Normal file
40
tests/Doctrine/Tests/ORM/Mapping/Symfony/XmlDriverTest.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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\Tests\ORM\Mapping\Symfony;
|
||||
|
||||
use \Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver;
|
||||
|
||||
/**
|
||||
* @group DDC-1418
|
||||
*/
|
||||
class XmlDriverTest extends AbstractDriverTest
|
||||
{
|
||||
protected function getFileExtension()
|
||||
{
|
||||
return '.orm.xml';
|
||||
}
|
||||
|
||||
protected function getDriver(array $paths = array())
|
||||
{
|
||||
$driver = new SimplifiedXmlDriver(array_flip($paths));
|
||||
|
||||
return $driver;
|
||||
}
|
||||
}
|
40
tests/Doctrine/Tests/ORM/Mapping/Symfony/YamlDriverTest.php
Normal file
40
tests/Doctrine/Tests/ORM/Mapping/Symfony/YamlDriverTest.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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\Tests\ORM\Mapping\Symfony;
|
||||
|
||||
use \Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver;
|
||||
|
||||
/**
|
||||
* @group DDC-1418
|
||||
*/
|
||||
class YamlDriverTest extends AbstractDriverTest
|
||||
{
|
||||
protected function getFileExtension()
|
||||
{
|
||||
return '.orm.yml';
|
||||
}
|
||||
|
||||
protected function getDriver(array $paths = array())
|
||||
{
|
||||
$driver = new SimplifiedYamlDriver(array_flip($paths));
|
||||
|
||||
return $driver;
|
||||
}
|
||||
}
|
@ -73,12 +73,13 @@ class ProxyClassGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
||||
$persister = $this->_getMockPersister();
|
||||
$this->_uowMock->setEntityPersister('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $persister);
|
||||
$proxy = $this->_proxyFactory->getProxy('Doctrine\Tests\Models\ECommerce\ECommerceFeature', $identifier);
|
||||
|
||||
$persister->expects($this->atLeastOnce())
|
||||
->method('load')
|
||||
->with($this->equalTo($identifier), $this->isInstanceOf($proxyClass))
|
||||
->will($this->returnValue(new \stdClass())); // fake return of entity instance
|
||||
$proxy->getId();
|
||||
$proxy->getDescription();
|
||||
$proxy->getProduct();
|
||||
}
|
||||
|
||||
public function testReferenceProxyRespectsMethodsParametersTypeHinting()
|
||||
@ -179,4 +180,4 @@ class SleepClass
|
||||
{
|
||||
return array('id');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
}
|
||||
|
||||
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)
|
||||
->useQueryCache(false);
|
||||
->useQueryCache(false);
|
||||
|
||||
foreach ($queryHints AS $name => $value) {
|
||||
$query->setHint($name, $value);
|
||||
@ -65,7 +65,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
}
|
||||
|
||||
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)
|
||||
->useQueryCache(false);
|
||||
->useQueryCache(false);
|
||||
|
||||
foreach ($queryHints AS $name => $value) {
|
||||
$query->setHint($name, $value);
|
||||
@ -729,12 +729,12 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = true",
|
||||
"SELECT b0_.id AS id0, b0_.booleanField AS booleanField1 FROM boolean_model b0_ WHERE b0_.booleanField = 'true'"
|
||||
"SELECT b0_.id AS id0, b0_.booleanField AS booleanField1 FROM boolean_model b0_ WHERE b0_.booleanField = true"
|
||||
);
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = false",
|
||||
"SELECT b0_.id AS id0, b0_.booleanField AS booleanField1 FROM boolean_model b0_ WHERE b0_.booleanField = 'false'"
|
||||
"SELECT b0_.id AS id0, b0_.booleanField AS booleanField1 FROM boolean_model b0_ WHERE b0_.booleanField = false"
|
||||
);
|
||||
|
||||
$this->_em->getConnection()->setDatabasePlatform($oldPlat);
|
||||
@ -1095,6 +1095,162 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"Doctrine\ORM\Query\QueryException"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeJoinInRootClassWithDisabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p',
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c1_.car_id AS car_id3, c2_.salary AS salary4, c2_.department AS department5, c2_.startDate AS startDate6, c0_.discr AS discr7, c0_.spouse_id AS spouse_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id',
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeJoinInRootClassWithEnabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p',
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_',
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeJoinInChildClassWithDisabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c2_.car_id AS car_id6, c0_.discr AS discr7, c0_.spouse_id AS spouse_id8 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id',
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeJoinInChildClassWithEnabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c0_.discr AS discr5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id',
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeJoinInLeafClassWithDisabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT m FROM Doctrine\Tests\Models\Company\CompanyManager m',
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c2_.car_id AS car_id8 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id',
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeJoinInLeafClassWithEnabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT m FROM Doctrine\Tests\Models\Company\CompanyManager m',
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id',
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeSingleTableInRootClassWithDisabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6, c0_.salesPerson_id AS salesPerson_id7 FROM company_contracts c0_ WHERE c0_.discr IN ('fix', 'flexible', 'flexultra')",
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeSingleTableInRootClassWithEnabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c0_.hoursWorked AS hoursWorked3, c0_.pricePerHour AS pricePerHour4, c0_.maxPrice AS maxPrice5, c0_.discr AS discr6 FROM company_contracts c0_ WHERE c0_.discr IN ('fix', 'flexible', 'flexultra')",
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeSingleTableInChildClassWithDisabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT fc FROM Doctrine\Tests\Models\Company\CompanyFlexContract fc',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5, c0_.salesPerson_id AS salesPerson_id6 FROM company_contracts c0_ WHERE c0_.discr IN ('flexible', 'flexultra')",
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeSingleTableInChildClassWithEnabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT fc FROM Doctrine\Tests\Models\Company\CompanyFlexContract fc',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5 FROM company_contracts c0_ WHERE c0_.discr IN ('flexible', 'flexultra')",
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeSingleTableInLeafClassWithDisabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT fuc FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract fuc',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5, c0_.salesPerson_id AS salesPerson_id6 FROM company_contracts c0_ WHERE c0_.discr IN ('flexultra')",
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeSingleTableInLeafClassWithEnabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT fuc FROM Doctrine\Tests\Models\Company\CompanyFlexUltraContract fuc',
|
||||
"SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.hoursWorked AS hoursWorked2, c0_.pricePerHour AS pricePerHour3, c0_.maxPrice AS maxPrice4, c0_.discr AS discr5 FROM company_contracts c0_ WHERE c0_.discr IN ('flexultra')",
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1161
|
||||
*/
|
||||
public function testSelfReferenceWithOneToOneDoesNotDuplicateAlias()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT p, pp FROM Doctrine\Tests\Models\Company\CompanyPerson p JOIN p.spouse pp',
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c1_.car_id AS car_id3, c2_.salary AS salary4, c2_.department AS department5, c2_.startDate AS startDate6, c3_.id AS id7, c3_.name AS name8, c4_.title AS title9, c4_.car_id AS car_id10, c5_.salary AS salary11, c5_.department AS department12, c5_.startDate AS startDate13, c0_.discr AS discr14, c0_.spouse_id AS spouse_id15, c3_.discr AS discr16, c3_.spouse_id AS spouse_id17 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ ON c0_.spouse_id = c3_.id LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id",
|
||||
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,6 +21,7 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->_tmpDir = \sys_get_temp_dir();
|
||||
\mkdir($this->_tmpDir . \DIRECTORY_SEPARATOR . $this->_namespace);
|
||||
$this->_generator = new EntityGenerator();
|
||||
$this->_generator->setAnnotationPrefix("");
|
||||
$this->_generator->setGenerateAnnotations(true);
|
||||
$this->_generator->setGenerateStubMethods(true);
|
||||
$this->_generator->setRegenerateEntityIfExists(false);
|
||||
@ -179,14 +180,15 @@ class EntityGeneratorTest extends \Doctrine\Tests\OrmTestCase
|
||||
|
||||
public function testLoadPrefixedMetadata()
|
||||
{
|
||||
$this->_generator->setAnnotationPrefix('orm:');
|
||||
$this->_generator->setAnnotationPrefix('ORM\\');
|
||||
$metadata = $this->generateBookEntityFixture();
|
||||
|
||||
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
|
||||
$driver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, array());
|
||||
|
||||
$book = $this->newInstance($metadata);
|
||||
|
||||
$cm = new \Doctrine\ORM\Mapping\ClassMetadata($metadata->name);
|
||||
$driver = $this->createAnnotationDriver(array(), 'orm');
|
||||
$driver->loadMetadataForClass($cm->name, $cm);
|
||||
|
||||
$this->assertEquals($cm->columnNames, $metadata->columnNames);
|
||||
|
@ -98,6 +98,8 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
|
||||
|
||||
public function testExportDirectoryAndFilesAreCreated()
|
||||
{
|
||||
$this->_deleteDirectory(__DIR__ . '/export/'.$this->_getType());
|
||||
|
||||
$type = $this->_getType();
|
||||
$metadataDriver = $this->_createMetadataDriver($type, __DIR__ . '/' . $type);
|
||||
$em = $this->_createEntityManager($metadataDriver);
|
||||
@ -113,6 +115,7 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
|
||||
$exporter = $cme->getExporter($type, __DIR__ . '/export/' . $type);
|
||||
if ($type === 'annotation') {
|
||||
$entityGenerator = new EntityGenerator();
|
||||
$entityGenerator->setAnnotationPrefix("");
|
||||
$exporter->setEntityGenerator($entityGenerator);
|
||||
}
|
||||
$this->_extension = $exporter->getExtension();
|
||||
@ -139,6 +142,8 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
|
||||
$cmf = $this->_createClassMetadataFactory($em, $type);
|
||||
$metadata = $cmf->getAllMetadata();
|
||||
|
||||
$this->assertEquals(1, count($metadata));
|
||||
|
||||
$class = current($metadata);
|
||||
|
||||
$this->assertEquals('Doctrine\Tests\ORM\Tools\Export\ExportedUser', $class->name);
|
||||
@ -322,8 +327,7 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$type = $this->_getType();
|
||||
$this->_deleteDirectory(__DIR__ . '/export/'.$this->_getType());
|
||||
# $this->_deleteDirectory(__DIR__ . '/export/'.$this->_getType());
|
||||
}
|
||||
|
||||
protected function _deleteDirectory($path)
|
||||
|
@ -11,6 +11,7 @@ abstract class OrmTestCase extends DoctrineTestCase
|
||||
{
|
||||
/** The metadata cache that is shared between all ORM tests (except functional tests). */
|
||||
private static $_metadataCacheImpl = null;
|
||||
|
||||
/** The query cache that is shared between all ORM tests (except functional tests). */
|
||||
private static $_queryCacheImpl = null;
|
||||
|
||||
@ -66,30 +67,31 @@ abstract class OrmTestCase extends DoctrineTestCase
|
||||
*/
|
||||
protected function _getTestEntityManager($conn = null, $conf = null, $eventManager = null, $withSharedMetadata = true)
|
||||
{
|
||||
$metadataCache = $withSharedMetadata
|
||||
? self::getSharedMetadataCacheImpl()
|
||||
: new \Doctrine\Common\Cache\ArrayCache;
|
||||
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
if($withSharedMetadata) {
|
||||
$config->setMetadataCacheImpl(self::getSharedMetadataCacheImpl());
|
||||
} else {
|
||||
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
|
||||
}
|
||||
|
||||
|
||||
$config->setMetadataCacheImpl($metadataCache);
|
||||
$config->setMetadataDriverImpl($config->newDefaultAnnotationDriver());
|
||||
|
||||
$config->setQueryCacheImpl(self::getSharedQueryCacheImpl());
|
||||
$config->setProxyDir(__DIR__ . '/Proxies');
|
||||
$config->setProxyNamespace('Doctrine\Tests\Proxies');
|
||||
$eventManager = new \Doctrine\Common\EventManager();
|
||||
|
||||
if ($conn === null) {
|
||||
$conn = array(
|
||||
'driverClass' => 'Doctrine\Tests\Mocks\DriverMock',
|
||||
'driverClass' => 'Doctrine\Tests\Mocks\DriverMock',
|
||||
'wrapperClass' => 'Doctrine\Tests\Mocks\ConnectionMock',
|
||||
'user' => 'john',
|
||||
'password' => 'wayne'
|
||||
'user' => 'john',
|
||||
'password' => 'wayne'
|
||||
);
|
||||
}
|
||||
|
||||
if (is_array($conn)) {
|
||||
$conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, $eventManager);
|
||||
}
|
||||
|
||||
return \Doctrine\Tests\Mocks\EntityManagerMock::create($conn, $config, $eventManager);
|
||||
}
|
||||
|
||||
@ -98,6 +100,7 @@ abstract class OrmTestCase extends DoctrineTestCase
|
||||
if (self::$_metadataCacheImpl === null) {
|
||||
self::$_metadataCacheImpl = new \Doctrine\Common\Cache\ArrayCache;
|
||||
}
|
||||
|
||||
return self::$_metadataCacheImpl;
|
||||
}
|
||||
|
||||
@ -106,6 +109,7 @@ abstract class OrmTestCase extends DoctrineTestCase
|
||||
if (self::$_queryCacheImpl === null) {
|
||||
self::$_queryCacheImpl = new \Doctrine\Common\Cache\ArrayCache;
|
||||
}
|
||||
|
||||
return self::$_queryCacheImpl;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user