Merge branch 'master' into innerjoin-on-fetch-eager
Conflicts: lib/Doctrine/ORM/Persisters/BasicEntityPersister.php
This commit is contained in:
commit
53386e5247
@ -1,3 +1,17 @@
|
||||
# ResultCache implementation rewritten
|
||||
|
||||
The result cache is completly rewritten and now works on the database result level, not inside the ORM AbstractQuery
|
||||
anymore. This means that for result cached queries the hydration will now always be performed again, regardless of
|
||||
the hydration mode. Affected areas are:
|
||||
|
||||
1. Fixes the problem that entities coming from the result cache were not registered in the UnitOfWork
|
||||
leading to problems during EntityManager#flush. Calls to EntityManager#merge are not necessary anymore.
|
||||
2. Affects the array hydrator which now includes the overhead of hydration compared to caching the final result.
|
||||
|
||||
The API is backwards compatible however most of the getter methods on the `AbstractQuery` object are now
|
||||
deprecated in favor of calling AbstractQuery#getQueryCacheProfile(). This method returns a `Doctrine\DBAL\Cache\QueryCacheProfile`
|
||||
instance with access to result cache driver, lifetime and cache key.
|
||||
|
||||
# EntityManager#getPartialReference() creates read-only entity
|
||||
|
||||
Entities returned from EntityManager#getPartialReference() are now marked as read-only if they
|
||||
|
@ -20,7 +20,8 @@
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\DBAL\Types\Type,
|
||||
Doctrine\ORM\Query\QueryException;
|
||||
Doctrine\ORM\Query\QueryException,
|
||||
Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||
|
||||
/**
|
||||
* Base contract for ORM queries. Base class for Query and NativeQuery.
|
||||
@ -91,34 +92,15 @@ abstract class AbstractQuery
|
||||
protected $_hydrationMode = self::HYDRATE_OBJECT;
|
||||
|
||||
/**
|
||||
* The locally set cache driver used for caching result sets of this query.
|
||||
*
|
||||
* @var CacheDriver
|
||||
* @param \Doctrine\DBAL\Cache\QueryCacheProfile
|
||||
*/
|
||||
protected $_resultCacheDriver;
|
||||
|
||||
/**
|
||||
* Boolean flag for whether or not to cache the results of this query.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $_useResultCache;
|
||||
|
||||
/**
|
||||
* @var string The id to store the result cache entry under.
|
||||
*/
|
||||
protected $_resultCacheId;
|
||||
protected $_queryCacheProfile;
|
||||
|
||||
/**
|
||||
* @var boolean Boolean value that indicates whether or not expire the result cache.
|
||||
*/
|
||||
protected $_expireResultCache = false;
|
||||
|
||||
/**
|
||||
* @var int Result Cache lifetime.
|
||||
*/
|
||||
protected $_resultCacheTTL;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
|
||||
*
|
||||
@ -260,7 +242,7 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a cache driver to be used for caching result sets.
|
||||
* Defines a cache driver to be used for caching result sets and implictly enables caching.
|
||||
*
|
||||
* @param Doctrine\Common\Cache\Cache $driver Cache driver
|
||||
* @return Doctrine\ORM\AbstractQuery
|
||||
@ -270,9 +252,10 @@ abstract class AbstractQuery
|
||||
if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) {
|
||||
throw ORMException::invalidResultCacheDriver();
|
||||
}
|
||||
$this->_resultCacheDriver = $resultCacheDriver;
|
||||
if ($resultCacheDriver) {
|
||||
$this->_useResultCache = true;
|
||||
if ($this->_queryCacheProfile) {
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver);
|
||||
} else {
|
||||
$this->_queryCacheProfile = new QueryCacheProfile(0, null, $resultCacheDriver);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
@ -280,12 +263,13 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Returns the cache driver used for caching result sets.
|
||||
*
|
||||
* @deprecated
|
||||
* @return Doctrine\Common\Cache\Cache Cache driver
|
||||
*/
|
||||
public function getResultCacheDriver()
|
||||
{
|
||||
if ($this->_resultCacheDriver) {
|
||||
return $this->_resultCacheDriver;
|
||||
if ($this->_queryCacheProfile && $this->_queryCacheProfile->getResultCacheDriver()) {
|
||||
return $this->_queryCacheProfile->getResultCacheDriver();
|
||||
} else {
|
||||
return $this->_em->getConfiguration()->getResultCacheImpl();
|
||||
}
|
||||
@ -296,18 +280,17 @@ abstract class AbstractQuery
|
||||
* how long and which ID to use for the cache entry.
|
||||
*
|
||||
* @param boolean $bool
|
||||
* @param integer $timeToLive
|
||||
* @param integer $lifetime
|
||||
* @param string $resultCacheId
|
||||
* @return Doctrine\ORM\AbstractQuery This query instance.
|
||||
*/
|
||||
public function useResultCache($bool, $timeToLive = null, $resultCacheId = null)
|
||||
public function useResultCache($bool, $lifetime = null, $resultCacheId = null)
|
||||
{
|
||||
$this->_useResultCache = $bool;
|
||||
if ($timeToLive) {
|
||||
$this->setResultCacheLifetime($timeToLive);
|
||||
}
|
||||
if ($resultCacheId) {
|
||||
$this->_resultCacheId = $resultCacheId;
|
||||
if ($bool) {
|
||||
$this->setResultCacheLifetime($lifetime);
|
||||
$this->setResultCacheId($resultCacheId);
|
||||
} else {
|
||||
$this->_queryCacheProfile = null;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
@ -315,27 +298,33 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Defines how long the result cache will be active before expire.
|
||||
*
|
||||
* @param integer $timeToLive How long the cache entry is valid.
|
||||
* @param integer $lifetime How long the cache entry is valid.
|
||||
* @return Doctrine\ORM\AbstractQuery This query instance.
|
||||
*/
|
||||
public function setResultCacheLifetime($timeToLive)
|
||||
public function setResultCacheLifetime($lifetime)
|
||||
{
|
||||
if ($timeToLive !== null) {
|
||||
$timeToLive = (int) $timeToLive;
|
||||
if ($lifetime === null) {
|
||||
$lifetime = 0;
|
||||
} else {
|
||||
$lifetime = (int)$lifetime;
|
||||
}
|
||||
if ($this->_queryCacheProfile) {
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setLifetime($lifetime);
|
||||
} else {
|
||||
$this->_queryCacheProfile = new QueryCacheProfile($lifetime);
|
||||
}
|
||||
|
||||
$this->_resultCacheTTL = $timeToLive;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the lifetime of resultset cache.
|
||||
*
|
||||
* @deprecated
|
||||
* @return integer
|
||||
*/
|
||||
public function getResultCacheLifetime()
|
||||
{
|
||||
return $this->_resultCacheTTL;
|
||||
return $this->_queryCacheProfile ? $this->_queryCacheProfile->getLifetime() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -360,6 +349,14 @@ abstract class AbstractQuery
|
||||
return $this->_expireResultCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return QueryCacheProfile
|
||||
*/
|
||||
public function getQueryCacheProfile()
|
||||
{
|
||||
return $this->_queryCacheProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the default fetch mode of an association for this query.
|
||||
*
|
||||
@ -548,7 +545,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @param array $params The query parameters.
|
||||
* @param integer $hydrationMode The hydration mode to use.
|
||||
* @return IterableResult
|
||||
* @return \Doctrine\ORM\Internal\Hydration\IterableResult
|
||||
*/
|
||||
public function iterate(array $params = array(), $hydrationMode = null)
|
||||
{
|
||||
@ -584,28 +581,6 @@ abstract class AbstractQuery
|
||||
$this->setParameters($params);
|
||||
}
|
||||
|
||||
// Check result cache
|
||||
if ($this->_useResultCache && $cacheDriver = $this->getResultCacheDriver()) {
|
||||
list($key, $hash) = $this->getResultCacheId();
|
||||
$cached = $this->_expireResultCache ? false : $cacheDriver->fetch($hash);
|
||||
|
||||
if ($cached === false || !isset($cached[$key])) {
|
||||
// Cache miss.
|
||||
$stmt = $this->_doExecute();
|
||||
|
||||
$result = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
|
||||
$stmt, $this->_resultSetMapping, $this->_hints
|
||||
);
|
||||
|
||||
$cacheDriver->save($hash, array($key => $result), $this->_resultCacheTTL);
|
||||
|
||||
return $result;
|
||||
} else {
|
||||
// Cache hit.
|
||||
return $cached[$key];
|
||||
}
|
||||
}
|
||||
|
||||
$stmt = $this->_doExecute();
|
||||
|
||||
if (is_numeric($stmt)) {
|
||||
@ -627,43 +602,23 @@ abstract class AbstractQuery
|
||||
*/
|
||||
public function setResultCacheId($id)
|
||||
{
|
||||
$this->_resultCacheId = $id;
|
||||
if ($this->_queryCacheProfile) {
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setCacheKey($id);
|
||||
} else {
|
||||
$this->_queryCacheProfile = new QueryCacheProfile(0, $id);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result cache id to use to store the result set cache entry.
|
||||
* Will return the configured id if it exists otherwise a hash will be
|
||||
* automatically generated for you.
|
||||
* Get the result cache id to use to store the result set cache entry if set.
|
||||
*
|
||||
* @return array ($key, $hash)
|
||||
* @deprecated
|
||||
* @return string
|
||||
*/
|
||||
protected function getResultCacheId()
|
||||
public function getResultCacheId()
|
||||
{
|
||||
if ($this->_resultCacheId) {
|
||||
return array($this->_resultCacheId, $this->_resultCacheId);
|
||||
} else {
|
||||
$params = $this->_params;
|
||||
foreach ($params AS $key => $value) {
|
||||
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value))) {
|
||||
if ($this->_em->getUnitOfWork()->getEntityState($value) == UnitOfWork::STATE_MANAGED) {
|
||||
$idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
} else {
|
||||
$class = $this->_em->getClassMetadata(get_class($value));
|
||||
$idValues = $class->getIdentifierValues($value);
|
||||
}
|
||||
$params[$key] = $idValues;
|
||||
} else {
|
||||
$params[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$sql = $this->getSql();
|
||||
ksort($this->_hints);
|
||||
$key = implode(";", (array)$sql) . var_export($params, true) .
|
||||
var_export($this->_hints, true)."&hydrationMode=".$this->_hydrationMode;
|
||||
return array($key, md5($key));
|
||||
}
|
||||
return $this->_queryCacheProfile ? $this->_queryCacheProfile->getCacheKey() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,27 +209,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
$this->_attributes['metadataDriverImpl'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache driver implementation that is used for query result caching.
|
||||
*
|
||||
* @return \Doctrine\Common\Cache\Cache
|
||||
*/
|
||||
public function getResultCacheImpl()
|
||||
{
|
||||
return isset($this->_attributes['resultCacheImpl']) ?
|
||||
$this->_attributes['resultCacheImpl'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for query result caching.
|
||||
*
|
||||
* @param \Doctrine\Common\Cache\Cache $cacheImpl
|
||||
*/
|
||||
public function setResultCacheImpl(Cache $cacheImpl)
|
||||
{
|
||||
$this->_attributes['resultCacheImpl'] = $cacheImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache driver implementation that is used for the query cache (SQL cache).
|
||||
*
|
||||
|
@ -19,14 +19,16 @@
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use \Doctrine\Common\EventSubscriber;
|
||||
use \LogicException;
|
||||
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
|
||||
* @link www.doctrine-project.org
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @since 2.2
|
||||
*/
|
||||
class EntityEventDelegator implements EventSubscriber
|
||||
{
|
||||
@ -54,17 +56,23 @@ class EntityEventDelegator implements EventSubscriber
|
||||
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.");
|
||||
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);
|
||||
$hash = spl_object_hash($listener);
|
||||
$entities = array_flip((array) $entities);
|
||||
|
||||
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));
|
||||
$this->listeners[$event][$hash] = array(
|
||||
'listener' => $listener,
|
||||
'entities' => $entities
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,6 +81,7 @@ class EntityEventDelegator implements EventSubscriber
|
||||
* interested in and added as a listener for these events.
|
||||
*
|
||||
* @param Doctrine\Common\EventSubscriber $subscriber The subscriber.
|
||||
* @param array $entities
|
||||
*/
|
||||
public function addEventSubscriber(EventSubscriber $subscriber, $entities)
|
||||
{
|
||||
@ -87,24 +96,27 @@ class EntityEventDelegator implements EventSubscriber
|
||||
public function getSubscribedEvents()
|
||||
{
|
||||
$this->frozen = true;
|
||||
|
||||
return array_keys($this->listeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate the event to an appropriate listener
|
||||
*
|
||||
* @param $eventName
|
||||
* @param $event
|
||||
* @param string $eventName
|
||||
* @param array $args
|
||||
* @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);
|
||||
}
|
||||
|
||||
if ( ! isset($listenerData['entities'][$class])) continue;
|
||||
|
||||
$listenerData['listener']->$eventName($event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,42 +19,59 @@
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions
|
||||
* of entities.
|
||||
*
|
||||
* @since 2.0
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class LifecycleEventArgs extends \Doctrine\Common\EventArgs
|
||||
class LifecycleEventArgs extends EventArgs
|
||||
{
|
||||
/**
|
||||
* @var EntityManager
|
||||
* @var Doctrine\ORM\EntityManager
|
||||
*/
|
||||
private $_em;
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
private $_entity;
|
||||
private $entity;
|
||||
|
||||
public function __construct($entity, $em)
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param object $entity
|
||||
* @param Doctrine\ORM\EntityManager $em
|
||||
*/
|
||||
public function __construct($entity, EntityManager $em)
|
||||
{
|
||||
$this->_entity = $entity;
|
||||
$this->_em = $em;
|
||||
$this->entity = $entity;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retireve associated Entity.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function getEntity()
|
||||
{
|
||||
return $this->_entity;
|
||||
return $this->entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityManager
|
||||
* Retrieve associated EntityManager.
|
||||
*
|
||||
* @return Doctrine\ORM\EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
return $this->_em;
|
||||
return $this->em;
|
||||
}
|
||||
}
|
@ -1,9 +1,25 @@
|
||||
<?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\EventArgs;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
|
||||
@ -11,32 +27,36 @@ use Doctrine\ORM\EntityManager;
|
||||
* Class that holds event arguments for a loadMetadata event.
|
||||
*
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @since 2.0
|
||||
* @since 2.0
|
||||
*/
|
||||
class LoadClassMetadataEventArgs extends EventArgs
|
||||
{
|
||||
/**
|
||||
* @var ClassMetadata
|
||||
* @var Doctrine\ORM\Mapping\ClassMetadata
|
||||
*/
|
||||
private $classMetadata;
|
||||
|
||||
/**
|
||||
* @var EntityManager
|
||||
* @var Doctrine\ORM\EntityManager
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @param ClassMetadataInfo $classMetadata
|
||||
* @param EntityManager $em
|
||||
* Constructor.
|
||||
*
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadataInfo $classMetadata
|
||||
* @param Doctrine\ORM\EntityManager $em
|
||||
*/
|
||||
public function __construct(ClassMetadataInfo $classMetadata, EntityManager $em)
|
||||
{
|
||||
$this->classMetadata = $classMetadata;
|
||||
$this->em = $em;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadataInfo
|
||||
* Retrieve associated ClassMetadata.
|
||||
*
|
||||
* @return Doctrine\ORM\Mapping\ClassMetadataInfo
|
||||
*/
|
||||
public function getClassMetadata()
|
||||
{
|
||||
@ -44,7 +64,9 @@ class LoadClassMetadataEventArgs extends EventArgs
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityManager
|
||||
* Retrieve associated EntityManager.
|
||||
*
|
||||
* @return Doctrine\ORM\EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
|
@ -15,7 +15,7 @@
|
||||
* 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;
|
||||
|
||||
@ -23,16 +23,15 @@ namespace Doctrine\ORM\Event;
|
||||
* Provides event arguments for the onClear event.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManager
|
||||
* @var Doctrine\ORM\EntityManager
|
||||
*/
|
||||
private $em;
|
||||
|
||||
@ -42,16 +41,21 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
||||
private $entityClass;
|
||||
|
||||
/**
|
||||
* @param \Doctrine\ORM\EntityManager $em
|
||||
* Constructor.
|
||||
*
|
||||
* @param Doctrine\ORM\EntityManager $em
|
||||
* @param string $entityClass Optional entity class
|
||||
*/
|
||||
public function __construct($em, $entityClass = null)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->em = $em;
|
||||
$this->entityClass = $entityClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\ORM\EntityManager
|
||||
* Retrieve associated EntityManager.
|
||||
*
|
||||
* @return Doctrine\ORM\EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
@ -75,6 +79,6 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
||||
*/
|
||||
public function clearsAllEntities()
|
||||
{
|
||||
return $this->entityClass === null;
|
||||
return ($this->entityClass === null);
|
||||
}
|
||||
}
|
@ -21,37 +21,45 @@
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* Provides event arguments for the preFlush event.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Roman Borschel <roman@code-factory.de>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class OnFlushEventArgs extends \Doctrine\Common\EventArgs
|
||||
{
|
||||
/**
|
||||
* @var EntityManager
|
||||
* @var Doctirne\ORM\EntityManager
|
||||
*/
|
||||
private $_em;
|
||||
private $em;
|
||||
|
||||
//private $_entitiesToPersist = array();
|
||||
//private $_entitiesToRemove = array();
|
||||
//private $entitiesToPersist = array();
|
||||
//private $entitiesToRemove = array();
|
||||
|
||||
public function __construct($em)
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Doctrine\ORM\EntityManager $em
|
||||
*/
|
||||
public function __construct(EntityManager $em)
|
||||
{
|
||||
$this->_em = $em;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityManager
|
||||
* Retrieve associated EntityManager.
|
||||
*
|
||||
* @return Doctrine\ORM\EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
return $this->_em;
|
||||
return $this->em;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -17,9 +17,10 @@
|
||||
* 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\ORM\EntityManager;
|
||||
use Doctrine\Common\EventArgs;
|
||||
|
||||
@ -27,20 +28,21 @@ use Doctrine\Common\EventArgs;
|
||||
* Provides event arguments for the postFlush event.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.com
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @author Daniel Freudenberger <df@rebuy.de>
|
||||
*/
|
||||
class PostFlushEventArgs extends EventArgs
|
||||
{
|
||||
/**
|
||||
* @var EntityManager
|
||||
* @var Doctrine\ORM\EntityManager
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @param EntityManager $em
|
||||
* Constructor.
|
||||
*
|
||||
* @param Doctrine\ORM\EntityManager $em
|
||||
*/
|
||||
public function __construct(EntityManager $em)
|
||||
{
|
||||
@ -48,7 +50,9 @@ class PostFlushEventArgs extends EventArgs
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityManager
|
||||
* Retrieve associated EntityManager.
|
||||
*
|
||||
* @return Doctrine\ORM\EntityManager
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
|
@ -1,4 +1,23 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* 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;
|
||||
|
||||
@ -8,42 +27,50 @@ use Doctrine\Common\EventArgs,
|
||||
/**
|
||||
* Class that holds event arguments for a preInsert/preUpdate event.
|
||||
*
|
||||
* @author Guilherme Blanco <guilehrmeblanco@hotmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @since 2.0
|
||||
* @since 2.0
|
||||
*/
|
||||
class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $_entityChangeSet;
|
||||
private $entityChangeSet;
|
||||
|
||||
/**
|
||||
*
|
||||
* Constructor.
|
||||
*
|
||||
* @param object $entity
|
||||
* @param EntityManager $em
|
||||
* @param Doctrine\ORM\EntityManager $em
|
||||
* @param array $changeSet
|
||||
*/
|
||||
public function __construct($entity, $em, array &$changeSet)
|
||||
public function __construct($entity, EntityManager $em, array &$changeSet)
|
||||
{
|
||||
parent::__construct($entity, $em);
|
||||
$this->_entityChangeSet = &$changeSet;
|
||||
}
|
||||
|
||||
public function getEntityChangeSet()
|
||||
{
|
||||
return $this->_entityChangeSet;
|
||||
|
||||
$this->entityChangeSet = &$changeSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Field has a changeset?
|
||||
* Retrieve entity changeset.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEntityChangeSet()
|
||||
{
|
||||
return $this->entityChangeSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if field has a changeset.
|
||||
*
|
||||
* @return bool
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasChangedField($field)
|
||||
{
|
||||
return isset($this->_entityChangeSet[$field]);
|
||||
return isset($this->entityChangeSet[$field]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,9 +81,9 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
*/
|
||||
public function getOldValue($field)
|
||||
{
|
||||
$this->_assertValidField($field);
|
||||
$this->assertValidField($field);
|
||||
|
||||
return $this->_entityChangeSet[$field][0];
|
||||
return $this->entityChangeSet[$field][0];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,9 +94,9 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
*/
|
||||
public function getNewValue($field)
|
||||
{
|
||||
$this->_assertValidField($field);
|
||||
$this->assertValidField($field);
|
||||
|
||||
return $this->_entityChangeSet[$field][1];
|
||||
return $this->entityChangeSet[$field][1];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,18 +107,24 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
*/
|
||||
public function setNewValue($field, $value)
|
||||
{
|
||||
$this->_assertValidField($field);
|
||||
$this->assertValidField($field);
|
||||
|
||||
$this->_entityChangeSet[$field][1] = $value;
|
||||
$this->entityChangeSet[$field][1] = $value;
|
||||
}
|
||||
|
||||
private function _assertValidField($field)
|
||||
/**
|
||||
* Assert the field exists in changeset.
|
||||
*
|
||||
* @param string $field
|
||||
*/
|
||||
private function assertValidField($field)
|
||||
{
|
||||
if (!isset($this->_entityChangeSet[$field])) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Field '".$field."' is not a valid field of the entity ".
|
||||
"'".get_class($this->getEntity())."' in PreUpdateEventArgs."
|
||||
);
|
||||
if ( ! isset($this->entityChangeSet[$field])) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Field "%s" is not a valid field of the entity "%s" in PreUpdateEventArgs.',
|
||||
$field,
|
||||
get_class($this->getEntity())
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\ORMException;
|
||||
|
||||
/**
|
||||
@ -42,46 +43,29 @@ class AssignedGenerator extends AbstractIdGenerator
|
||||
*/
|
||||
public function generate(EntityManager $em, $entity)
|
||||
{
|
||||
$class = $em->getClassMetadata(get_class($entity));
|
||||
$class = $em->getClassMetadata(get_class($entity));
|
||||
$idFields = $class->getIdentifierFieldNames();
|
||||
$identifier = array();
|
||||
if ($class->isIdentifierComposite) {
|
||||
$idFields = $class->getIdentifierFieldNames();
|
||||
foreach ($idFields as $idField) {
|
||||
$value = $class->reflFields[$idField]->getValue($entity);
|
||||
if (isset($value)) {
|
||||
if (isset($class->associationMappings[$idField])) {
|
||||
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::entityMissingAssignedIdForField($entity, $idField);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$idField = $class->identifier[0];
|
||||
|
||||
foreach ($idFields as $idField) {
|
||||
$value = $class->reflFields[$idField]->getValue($entity);
|
||||
if (isset($value)) {
|
||||
if (isset($class->associationMappings[$idField])) {
|
||||
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 {
|
||||
|
||||
if ( ! isset($value)) {
|
||||
throw ORMException::entityMissingAssignedIdForField($entity, $idField);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($class->associationMappings[$idField])) {
|
||||
if ( ! $em->getUnitOfWork()->isInIdentityMap($value)) {
|
||||
throw ORMException::entityMissingForeignAssignedId($entity, $value);
|
||||
}
|
||||
|
||||
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
|
||||
$value = current($em->getUnitOfWork()->getEntityIdentifier($value));
|
||||
}
|
||||
|
||||
$identifier[$idField] = $value;
|
||||
}
|
||||
|
||||
return $identifier;
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
if (!isset($this->_hints['deferEagerLoad'])) {
|
||||
$this->_hints['deferEagerLoad'] = true;
|
||||
}
|
||||
|
||||
|
||||
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
|
||||
$this->_identifierMap[$dqlAlias] = array();
|
||||
$this->_idTemplate[$dqlAlias] = '';
|
||||
@ -116,13 +116,13 @@ class ObjectHydrator extends AbstractHydrator
|
||||
protected function _cleanup()
|
||||
{
|
||||
$eagerLoad = (isset($this->_hints['deferEagerLoad'])) && $this->_hints['deferEagerLoad'] == true;
|
||||
|
||||
|
||||
parent::_cleanup();
|
||||
$this->_identifierMap =
|
||||
$this->_initializedCollections =
|
||||
$this->_existingCollections =
|
||||
$this->_resultPointers = array();
|
||||
|
||||
|
||||
if ($eagerLoad) {
|
||||
$this->_em->getUnitOfWork()->triggerEagerLoads();
|
||||
}
|
||||
@ -192,7 +192,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
|
||||
/**
|
||||
* Gets an entity instance.
|
||||
*
|
||||
*
|
||||
* @param $data The instance data.
|
||||
* @param $dqlAlias The DQL alias of the entity's class.
|
||||
* @return object The entity.
|
||||
@ -205,12 +205,12 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$className = $this->_ce[$className]->discriminatorMap[$data[$discrColumn]];
|
||||
unset($data[$discrColumn]);
|
||||
}
|
||||
|
||||
|
||||
if (isset($this->_hints[Query::HINT_REFRESH_ENTITY]) && isset($this->_rootAliases[$dqlAlias])) {
|
||||
$class = $this->_ce[$className];
|
||||
$this->registerManaged($class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
|
||||
}
|
||||
|
||||
|
||||
return $this->_uow->createEntity($className, $data, $this->_hints);
|
||||
}
|
||||
|
||||
@ -240,7 +240,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* Gets a ClassMetadata instance from the local cache.
|
||||
* If the instance is not yet in the local cache, it is loaded into the
|
||||
* local cache.
|
||||
*
|
||||
*
|
||||
* @param string $className The name of the class.
|
||||
* @return ClassMetadata
|
||||
*/
|
||||
@ -254,21 +254,21 @@ class ObjectHydrator extends AbstractHydrator
|
||||
|
||||
/**
|
||||
* Hydrates a single row in an SQL result set.
|
||||
*
|
||||
*
|
||||
* @internal
|
||||
* First, the data of the row is split into chunks where each chunk contains data
|
||||
* that belongs to a particular component/class. Afterwards, all these chunks
|
||||
* are processed, one after the other. For each chunk of class data only one of the
|
||||
* following code paths is executed:
|
||||
*
|
||||
*
|
||||
* Path A: The data chunk belongs to a joined/associated object and the association
|
||||
* is collection-valued.
|
||||
* Path B: The data chunk belongs to a joined/associated object and the association
|
||||
* is single-valued.
|
||||
* Path C: The data chunk belongs to a root result element/object that appears in the topmost
|
||||
* level of the hydrated result. A typical example are the objects of the type
|
||||
* specified by the FROM clause in a DQL query.
|
||||
*
|
||||
* specified by the FROM clause in a DQL query.
|
||||
*
|
||||
* @param array $data The data of the row to process.
|
||||
* @param array $cache The cache to use.
|
||||
* @param array $result The result array to fill.
|
||||
@ -369,10 +369,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$this->_resultPointers[$dqlAlias] = $reflFieldValue[$index];
|
||||
}
|
||||
} else if ( ! $reflField->getValue($parentObject)) {
|
||||
$coll = new PersistentCollection($this->_em, $this->_ce[$entityName], new ArrayCollection);
|
||||
$coll->setOwner($parentObject, $relation);
|
||||
$reflField->setValue($parentObject, $coll);
|
||||
$this->_uow->setOriginalEntityProperty($oid, $relationField, $coll);
|
||||
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField);
|
||||
}
|
||||
} else {
|
||||
// PATH B: Single-valued association
|
||||
|
@ -1111,25 +1111,25 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function getIdentifierColumnNames()
|
||||
{
|
||||
if ($this->isIdentifierComposite) {
|
||||
$columnNames = array();
|
||||
foreach ($this->identifier as $idField) {
|
||||
if (isset($this->associationMappings[$idField])) {
|
||||
// no composite pk as fk entity assumption:
|
||||
$columnNames[] = $this->associationMappings[$idField]['joinColumns'][0]['name'];
|
||||
} else {
|
||||
$columnNames[] = $this->fieldMappings[$idField]['columnName'];
|
||||
}
|
||||
$columnNames = array();
|
||||
|
||||
foreach ($this->identifier as $idProperty) {
|
||||
if (isset($this->fieldMappings[$idProperty])) {
|
||||
$columnNames[] = $this->fieldMappings[$idProperty]['columnName'];
|
||||
|
||||
continue;
|
||||
}
|
||||
return $columnNames;
|
||||
} else if(isset($this->fieldMappings[$this->identifier[0]])) {
|
||||
return array($this->fieldMappings[$this->identifier[0]]['columnName']);
|
||||
} else {
|
||||
// no composite pk as fk entity assumption:
|
||||
return array($this->associationMappings[$this->identifier[0]]['joinColumns'][0]['name']);
|
||||
|
||||
// Association defined as Id field
|
||||
$joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
|
||||
$assocColumnNames = array_map(function ($joinColumn) { return $joinColumn['name']; }, $joinColumns);
|
||||
|
||||
$columnNames = array_merge($columnNames, $assocColumnNames);
|
||||
}
|
||||
|
||||
return $columnNames;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the type of Id generator to use for the mapped class.
|
||||
*/
|
||||
@ -1904,6 +1904,42 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (possibly quoted) identifier column names for safe use in an SQL statement.
|
||||
*
|
||||
* @param AbstractPlatform $platform
|
||||
* @return array
|
||||
*/
|
||||
public function getQuotedIdentifierColumnNames($platform)
|
||||
{
|
||||
$quotedColumnNames = array();
|
||||
|
||||
foreach ($this->identifier as $idProperty) {
|
||||
if (isset($this->fieldMappings[$idProperty])) {
|
||||
$quotedColumnNames[] = isset($this->fieldMappings[$idProperty]['quoted'])
|
||||
? $platform->quoteIdentifier($this->fieldMappings[$idProperty]['columnName'])
|
||||
: $this->fieldMappings[$idProperty]['columnName'];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Association defined as Id field
|
||||
$joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
|
||||
$assocQuotedColumnNames = array_map(
|
||||
function ($joinColumn) {
|
||||
return isset($joinColumn['quoted'])
|
||||
? $platform->quoteIdentifier($joinColumn['name'])
|
||||
: $joinColumn['name'];
|
||||
},
|
||||
$joinColumns
|
||||
);
|
||||
|
||||
$quotedColumnNames = array_merge($quotedColumnNames, $assocQuotedColumnNames);
|
||||
}
|
||||
|
||||
return $quotedColumnNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (possibly quoted) column name of a mapped field for safe use
|
||||
* in an SQL statement.
|
||||
@ -1914,7 +1950,9 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function getQuotedColumnName($field, $platform)
|
||||
{
|
||||
return isset($this->fieldMappings[$field]['quoted']) ? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName']) : $this->fieldMappings[$field]['columnName'];
|
||||
return isset($this->fieldMappings[$field]['quoted'])
|
||||
? $platform->quoteIdentifier($this->fieldMappings[$field]['columnName'])
|
||||
: $this->fieldMappings[$field]['columnName'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,7 +89,7 @@ class XmlDriver extends AbstractFileDriver
|
||||
if (isset($xmlRoot['schema'])) {
|
||||
$metadata->table['schema'] = (string)$xmlRoot['schema'];
|
||||
}*/
|
||||
|
||||
|
||||
if (isset($xmlRoot['inheritance-type'])) {
|
||||
$inheritanceType = (string)$xmlRoot['inheritance-type'];
|
||||
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType));
|
||||
@ -327,6 +327,8 @@ class XmlDriver extends AbstractFileDriver
|
||||
|
||||
if (isset($oneToManyElement['index-by'])) {
|
||||
$mapping['indexBy'] = (string)$oneToManyElement['index-by'];
|
||||
} else if (isset($oneToManyElement->{'index-by'})) {
|
||||
throw new \InvalidArgumentException("<index-by /> is not a valid tag");
|
||||
}
|
||||
|
||||
$metadata->mapOneToMany($mapping);
|
||||
@ -432,8 +434,10 @@ class XmlDriver extends AbstractFileDriver
|
||||
$mapping['orderBy'] = $orderBy;
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement->{'index-by'})) {
|
||||
$mapping['indexBy'] = (string)$manyToManyElement->{'index-by'};
|
||||
if (isset($manyToManyElement['index-by'])) {
|
||||
$mapping['indexBy'] = (string)$manyToManyElement['index-by'];
|
||||
} else if (isset($manyToManyElement->{'index-by'})) {
|
||||
throw new \InvalidArgumentException("<index-by /> is not a valid tag");
|
||||
}
|
||||
|
||||
$metadata->mapManyToMany($mapping);
|
||||
|
@ -57,17 +57,17 @@ final class NativeQuery extends AbstractQuery
|
||||
*/
|
||||
protected function _doExecute()
|
||||
{
|
||||
$stmt = $this->_em->getConnection()->prepare($this->_sql);
|
||||
$params = $this->_params;
|
||||
foreach ($params as $key => $value) {
|
||||
if (isset($this->_paramTypes[$key])) {
|
||||
$stmt->bindValue($key, $value, $this->_paramTypes[$key]);
|
||||
} else {
|
||||
$stmt->bindValue($key, $value);
|
||||
$types = $this->_paramTypes;
|
||||
if ($params) {
|
||||
if (is_int(key($params))) {
|
||||
ksort($params);
|
||||
ksort($types);
|
||||
$params = array_values($params);
|
||||
$types = array_values($types);
|
||||
}
|
||||
}
|
||||
$stmt->execute();
|
||||
|
||||
return $stmt;
|
||||
return $this->_em->getConnection()->executeQuery($this->_sql, $params, $types, $this->_queryCacheProfile);
|
||||
}
|
||||
}
|
@ -93,21 +93,21 @@ final class PersistentCollection implements Collection
|
||||
|
||||
/**
|
||||
* Whether the collection has already been initialized.
|
||||
*
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $initialized = true;
|
||||
|
||||
|
||||
/**
|
||||
* The wrapped Collection instance.
|
||||
*
|
||||
*
|
||||
* @var Collection
|
||||
*/
|
||||
private $coll;
|
||||
|
||||
/**
|
||||
* Creates a new persistent collection.
|
||||
*
|
||||
*
|
||||
* @param EntityManager $em The EntityManager the collection will be associated with.
|
||||
* @param ClassMetadata $class The class descriptor of the entity type of this collection.
|
||||
* @param array The collection elements.
|
||||
@ -144,7 +144,7 @@ final class PersistentCollection implements Collection
|
||||
{
|
||||
return $this->owner;
|
||||
}
|
||||
|
||||
|
||||
public function getTypeClass()
|
||||
{
|
||||
return $this->typeClass;
|
||||
@ -154,7 +154,7 @@ final class PersistentCollection implements Collection
|
||||
* INTERNAL:
|
||||
* Adds an element to a collection during hydration. This will automatically
|
||||
* complete bidirectional associations in the case of a one-to-many association.
|
||||
*
|
||||
*
|
||||
* @param mixed $element The element to add.
|
||||
*/
|
||||
public function hydrateAdd($element)
|
||||
@ -172,7 +172,7 @@ final class PersistentCollection implements Collection
|
||||
$this->owner);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Sets a keyed element in the collection during hydration.
|
||||
@ -271,7 +271,7 @@ final class PersistentCollection implements Collection
|
||||
{
|
||||
return $this->association;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Marks this collection as changed/dirty.
|
||||
*/
|
||||
@ -306,17 +306,17 @@ final class PersistentCollection implements Collection
|
||||
{
|
||||
$this->isDirty = $dirty;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the initialized flag of the collection, forcing it into that state.
|
||||
*
|
||||
*
|
||||
* @param boolean $bool
|
||||
*/
|
||||
public function setInitialized($bool)
|
||||
{
|
||||
$this->initialized = $bool;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether this collection has been initialized.
|
||||
*
|
||||
@ -377,7 +377,7 @@ final class PersistentCollection implements Collection
|
||||
$this->em->getUnitOfWork()->getCollectionPersister($this->association)
|
||||
->deleteRows($this, $element);
|
||||
}*/
|
||||
|
||||
|
||||
$this->initialize();
|
||||
$removed = $this->coll->removeElement($element);
|
||||
if ($removed) {
|
||||
@ -410,7 +410,7 @@ final class PersistentCollection implements Collection
|
||||
->getCollectionPersister($this->association)
|
||||
->contains($this, $element);
|
||||
}
|
||||
|
||||
|
||||
$this->initialize();
|
||||
return $this->coll->contains($element);
|
||||
}
|
||||
@ -468,7 +468,7 @@ final class PersistentCollection implements Collection
|
||||
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
|
||||
return $this->em->getUnitOfWork()
|
||||
->getCollectionPersister($this->association)
|
||||
->count($this) + $this->coll->count();
|
||||
->count($this) + ($this->isDirty ? $this->coll->count() : 0);
|
||||
}
|
||||
|
||||
$this->initialize();
|
||||
@ -503,7 +503,7 @@ final class PersistentCollection implements Collection
|
||||
$this->initialize();
|
||||
return $this->coll->isEmpty();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -530,7 +530,7 @@ final class PersistentCollection implements Collection
|
||||
$this->initialize();
|
||||
return $this->coll->filter($p);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -548,7 +548,7 @@ final class PersistentCollection implements Collection
|
||||
$this->initialize();
|
||||
return $this->coll->partition($p);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -579,7 +579,7 @@ final class PersistentCollection implements Collection
|
||||
$this->takeSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by PHP when this collection is serialized. Ensures that only the
|
||||
* elements are properly serialized.
|
||||
@ -591,7 +591,7 @@ final class PersistentCollection implements Collection
|
||||
{
|
||||
return array('coll', 'initialized');
|
||||
}
|
||||
|
||||
|
||||
/* ArrayAccess implementation */
|
||||
|
||||
/**
|
||||
@ -629,12 +629,12 @@ final class PersistentCollection implements Collection
|
||||
{
|
||||
return $this->remove($offset);
|
||||
}
|
||||
|
||||
|
||||
public function key()
|
||||
{
|
||||
return $this->coll->key();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the element of the collection at the current iterator position.
|
||||
*/
|
||||
@ -642,7 +642,7 @@ final class PersistentCollection implements Collection
|
||||
{
|
||||
return $this->coll->current();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Moves the internal iterator position to the next element.
|
||||
*/
|
||||
@ -650,7 +650,7 @@ final class PersistentCollection implements Collection
|
||||
{
|
||||
return $this->coll->next();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the wrapped Collection instance.
|
||||
*/
|
||||
@ -672,7 +672,10 @@ final class PersistentCollection implements Collection
|
||||
*/
|
||||
public function slice($offset, $length = null)
|
||||
{
|
||||
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
|
||||
if ( ! $this->initialized &&
|
||||
! $this->isDirty &&
|
||||
$this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
|
||||
|
||||
return $this->em->getUnitOfWork()
|
||||
->getCollectionPersister($this->association)
|
||||
->slice($this, $offset, $length);
|
||||
|
@ -62,7 +62,7 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
{
|
||||
$columnName = $class->columnNames[$field];
|
||||
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
|
||||
$columnAlias = $this->getSQLColumnAlias($columnName);
|
||||
$this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name);
|
||||
|
||||
return $sql . ' AS ' . $columnAlias;
|
||||
@ -70,10 +70,9 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
||||
|
||||
protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className)
|
||||
{
|
||||
$columnAlias = $joinColumnName . $this->_sqlAliasCounter++;
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$this->_rsm->addMetaResult('r', $resultColumnName, $joinColumnName);
|
||||
$columnAlias = $this->getSQLColumnAlias($joinColumnName);
|
||||
$this->_rsm->addMetaResult('r', $columnAlias, $joinColumnName);
|
||||
|
||||
return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ class BasicEntityPersister
|
||||
|
||||
/**
|
||||
* The database platform.
|
||||
*
|
||||
*
|
||||
* @var Doctrine\DBAL\Platforms\AbstractPlatform
|
||||
*/
|
||||
protected $_platform;
|
||||
@ -110,12 +110,12 @@ class BasicEntityPersister
|
||||
* @var array
|
||||
*/
|
||||
protected $_queuedInserts = array();
|
||||
|
||||
|
||||
/**
|
||||
* ResultSetMapping that is used for all queries. Is generated lazily once per request.
|
||||
*
|
||||
*
|
||||
* TODO: Evaluate Caching in combination with the other cached SQL snippets.
|
||||
*
|
||||
*
|
||||
* @var Query\ResultSetMapping
|
||||
*/
|
||||
protected $_rsm;
|
||||
@ -123,7 +123,7 @@ class BasicEntityPersister
|
||||
/**
|
||||
* The map of column names to DBAL mapping types of all prepared columns used
|
||||
* when INSERTing or UPDATEing an entity.
|
||||
*
|
||||
*
|
||||
* @var array
|
||||
* @see _prepareInsertData($entity)
|
||||
* @see _prepareUpdateData($entity)
|
||||
@ -133,7 +133,7 @@ class BasicEntityPersister
|
||||
/**
|
||||
* The INSERT SQL statement used for entities handled by this persister.
|
||||
* This SQL is only generated once per request, if at all.
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_insertSql;
|
||||
@ -141,29 +141,29 @@ class BasicEntityPersister
|
||||
/**
|
||||
* The SELECT column list SQL fragment used for querying entities by this persister.
|
||||
* This SQL fragment is only generated once per request, if at all.
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_selectColumnListSql;
|
||||
|
||||
|
||||
/**
|
||||
* The JOIN SQL fragement used to eagerly load all many-to-one and one-to-one
|
||||
* associations configured as FETCH_EAGER, aswell as all inverse one-to-one associations.
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_selectJoinSql;
|
||||
|
||||
/**
|
||||
* Counter for creating unique SQL table and column aliases.
|
||||
*
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $_sqlAliasCounter = 0;
|
||||
|
||||
/**
|
||||
* Map from class names (FQCN) to the corresponding generated SQL table aliases.
|
||||
*
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_sqlTableAliases = array();
|
||||
@ -171,7 +171,7 @@ class BasicEntityPersister
|
||||
/**
|
||||
* Initializes a new <tt>BasicEntityPersister</tt> that uses the given EntityManager
|
||||
* and persists instances of the class described by the given ClassMetadata descriptor.
|
||||
*
|
||||
*
|
||||
* @param Doctrine\ORM\EntityManager $em
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $class
|
||||
*/
|
||||
@ -205,7 +205,7 @@ class BasicEntityPersister
|
||||
/**
|
||||
* Executes all queued entity insertions and returns any generated post-insert
|
||||
* identifiers that were created as a result of the insertions.
|
||||
*
|
||||
*
|
||||
* If no inserts are queued, invoking this method is a NOOP.
|
||||
*
|
||||
* @return array An array of any generated post-insert IDs. This will be an empty array
|
||||
@ -229,7 +229,7 @@ class BasicEntityPersister
|
||||
|
||||
if (isset($insertData[$tableName])) {
|
||||
$paramIndex = 1;
|
||||
|
||||
|
||||
foreach ($insertData[$tableName] as $column => $value) {
|
||||
$stmt->bindValue($paramIndex++, $value, $this->_columnTypes[$column]);
|
||||
}
|
||||
@ -257,7 +257,7 @@ class BasicEntityPersister
|
||||
|
||||
/**
|
||||
* Retrieves the default version value which was created
|
||||
* by the preceding INSERT statement and assigns it back in to the
|
||||
* by the preceding INSERT statement and assigns it back in to the
|
||||
* entities version field.
|
||||
*
|
||||
* @param object $entity
|
||||
@ -271,7 +271,7 @@ class BasicEntityPersister
|
||||
|
||||
/**
|
||||
* Fetch the current version value of a versioned entity.
|
||||
*
|
||||
*
|
||||
* @param Doctrine\ORM\Mapping\ClassMetadata $versionedClass
|
||||
* @param mixed $id
|
||||
* @return mixed
|
||||
@ -280,9 +280,9 @@ class BasicEntityPersister
|
||||
{
|
||||
$versionField = $versionedClass->versionField;
|
||||
$identifier = $versionedClass->getIdentifierColumnNames();
|
||||
|
||||
|
||||
$versionFieldColumnName = $versionedClass->getQuotedColumnName($versionField, $this->_platform);
|
||||
|
||||
|
||||
//FIXME: Order with composite keys might not be correct
|
||||
$sql = 'SELECT ' . $versionFieldColumnName
|
||||
. ' FROM ' . $versionedClass->getQuotedTableName($this->_platform)
|
||||
@ -299,7 +299,7 @@ class BasicEntityPersister
|
||||
* The data to update is retrieved through {@link _prepareUpdateData}.
|
||||
* Subclasses that override this method are supposed to obtain the update data
|
||||
* in the same way, through {@link _prepareUpdateData}.
|
||||
*
|
||||
*
|
||||
* Subclasses are also supposed to take care of versioning when overriding this method,
|
||||
* if necessary. The {@link _updateTable} method can be used to apply the data retrieved
|
||||
* from {@_prepareUpdateData} on the target tables, thereby optionally applying versioning.
|
||||
@ -310,7 +310,7 @@ class BasicEntityPersister
|
||||
{
|
||||
$updateData = $this->_prepareUpdateData($entity);
|
||||
$tableName = $this->_class->getTableName();
|
||||
|
||||
|
||||
if (isset($updateData[$tableName]) && $updateData[$tableName]) {
|
||||
$this->_updateTable(
|
||||
$entity, $this->_class->getQuotedTableName($this->_platform),
|
||||
@ -338,17 +338,17 @@ class BasicEntityPersister
|
||||
$set = $params = $types = array();
|
||||
|
||||
foreach ($updateData as $columnName => $value) {
|
||||
$set[] = (isset($this->_class->fieldNames[$columnName]))
|
||||
$set[] = (isset($this->_class->fieldNames[$columnName]))
|
||||
? $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform) . ' = ?'
|
||||
: $columnName . ' = ?';
|
||||
|
||||
|
||||
$params[] = $value;
|
||||
$types[] = $this->_columnTypes[$columnName];
|
||||
}
|
||||
|
||||
$where = array();
|
||||
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($entity);
|
||||
|
||||
|
||||
foreach ($this->_class->identifier as $idField) {
|
||||
if (isset($this->_class->associationMappings[$idField])) {
|
||||
$targetMapping = $this->_em->getClassMetadata($this->_class->associationMappings[$idField]['targetEntity']);
|
||||
@ -366,13 +366,13 @@ class BasicEntityPersister
|
||||
$versionField = $this->_class->versionField;
|
||||
$versionFieldType = $this->_class->fieldMappings[$versionField]['type'];
|
||||
$versionColumn = $this->_class->getQuotedColumnName($versionField, $this->_platform);
|
||||
|
||||
|
||||
if ($versionFieldType == Type::INTEGER) {
|
||||
$set[] = $versionColumn . ' = ' . $versionColumn . ' + 1';
|
||||
} else if ($versionFieldType == Type::DATETIME) {
|
||||
$set[] = $versionColumn . ' = CURRENT_TIMESTAMP';
|
||||
}
|
||||
|
||||
|
||||
$where[] = $versionColumn;
|
||||
$params[] = $this->_class->reflFields[$versionField]->getValue($entity);
|
||||
$types[] = $this->_class->fieldMappings[$versionField]['type'];
|
||||
@ -401,18 +401,18 @@ class BasicEntityPersister
|
||||
// @Todo this only covers scenarios with no inheritance or of the same level. Is there something
|
||||
// like self-referential relationship between different levels of an inheritance hierachy? I hope not!
|
||||
$selfReferential = ($mapping['targetEntity'] == $mapping['sourceEntity']);
|
||||
|
||||
|
||||
if ( ! $mapping['isOwningSide']) {
|
||||
$relatedClass = $this->_em->getClassMetadata($mapping['targetEntity']);
|
||||
$mapping = $relatedClass->associationMappings[$mapping['mappedBy']];
|
||||
$keys = array_keys($mapping['relationToTargetKeyColumns']);
|
||||
|
||||
|
||||
if ($selfReferential) {
|
||||
$otherKeys = array_keys($mapping['relationToSourceKeyColumns']);
|
||||
}
|
||||
} else {
|
||||
$keys = array_keys($mapping['relationToSourceKeyColumns']);
|
||||
|
||||
|
||||
if ($selfReferential) {
|
||||
$otherKeys = array_keys($mapping['relationToTargetKeyColumns']);
|
||||
}
|
||||
@ -420,13 +420,13 @@ class BasicEntityPersister
|
||||
|
||||
if ( ! isset($mapping['isOnDeleteCascade'])) {
|
||||
$this->_conn->delete(
|
||||
$this->_class->getQuotedJoinTableName($mapping, $this->_platform),
|
||||
$this->_class->getQuotedJoinTableName($mapping, $this->_platform),
|
||||
array_combine($keys, $identifier)
|
||||
);
|
||||
|
||||
if ($selfReferential) {
|
||||
$this->_conn->delete(
|
||||
$this->_class->getQuotedJoinTableName($mapping, $this->_platform),
|
||||
$this->_class->getQuotedJoinTableName($mapping, $this->_platform),
|
||||
array_combine($otherKeys, $identifier)
|
||||
);
|
||||
}
|
||||
@ -458,7 +458,7 @@ class BasicEntityPersister
|
||||
* Prepares the changeset of an entity for database insertion (UPDATE).
|
||||
*
|
||||
* The changeset is obtained from the currently running UnitOfWork.
|
||||
*
|
||||
*
|
||||
* During this preparation the array that is passed as the second parameter is filled with
|
||||
* <columnName> => <value> pairs, grouped by table name.
|
||||
*
|
||||
@ -493,7 +493,7 @@ class BasicEntityPersister
|
||||
|
||||
if (isset($this->_class->associationMappings[$field])) {
|
||||
$assoc = $this->_class->associationMappings[$field];
|
||||
|
||||
|
||||
// Only owning side of x-1 associations can have a FK column.
|
||||
if ( ! $assoc['isOwningSide'] || ! ($assoc['type'] & ClassMetadata::TO_ONE)) {
|
||||
continue;
|
||||
@ -501,7 +501,7 @@ class BasicEntityPersister
|
||||
|
||||
if ($newVal !== null) {
|
||||
$oid = spl_object_hash($newVal);
|
||||
|
||||
|
||||
if (isset($this->_queuedInserts[$oid]) || $uow->isScheduledForInsert($newVal)) {
|
||||
// The associated entity $newVal is not yet persisted, so we must
|
||||
// set $newVal = null, in order to insert a null value and schedule an
|
||||
@ -528,7 +528,7 @@ class BasicEntityPersister
|
||||
} else {
|
||||
$result[$owningTable][$sourceColumn] = $newValId[$targetClass->fieldNames[$targetColumn]];
|
||||
}
|
||||
|
||||
|
||||
$this->_columnTypes[$sourceColumn] = $targetClass->getTypeOfColumn($targetColumn);
|
||||
}
|
||||
} else {
|
||||
@ -537,7 +537,7 @@ class BasicEntityPersister
|
||||
$result[$this->getOwningTable($field)][$columnName] = $newVal;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -589,7 +589,7 @@ class BasicEntityPersister
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, $lockMode, $limit);
|
||||
list($params, $types) = $this->expandParameters($criteria);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params, $types);
|
||||
|
||||
|
||||
if ($entity !== null) {
|
||||
$hints[Query::HINT_REFRESH] = true;
|
||||
$hints[Query::HINT_REFRESH_ENTITY] = $entity;
|
||||
@ -597,7 +597,7 @@ class BasicEntityPersister
|
||||
|
||||
$hydrator = $this->_em->newHydrator($this->_selectJoinSql ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
|
||||
$entities = $hydrator->hydrateAll($stmt, $this->_rsm, $hints);
|
||||
|
||||
|
||||
return $entities ? $entities[0] : null;
|
||||
}
|
||||
|
||||
@ -626,17 +626,17 @@ class BasicEntityPersister
|
||||
// Mark inverse side as fetched in the hints, otherwise the UoW would
|
||||
// try to load it in a separate query (remember: to-one inverse sides can not be lazy).
|
||||
$hints = array();
|
||||
|
||||
|
||||
if ($isInverseSingleValued) {
|
||||
$hints['fetched'][$targetClass->name][$assoc['inversedBy']] = true;
|
||||
|
||||
|
||||
if ($targetClass->subClasses) {
|
||||
foreach ($targetClass->subClasses as $targetSubclassName) {
|
||||
$hints['fetched'][$targetSubclassName][$assoc['inversedBy']] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* cascade read-only status
|
||||
if ($this->_em->getUnitOfWork()->isReadOnly($sourceEntity)) {
|
||||
$hints[Query::HINT_READ_ONLY] = true;
|
||||
@ -652,7 +652,7 @@ class BasicEntityPersister
|
||||
} else {
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
|
||||
$owningAssoc = $targetClass->getAssociationMapping($assoc['mappedBy']);
|
||||
|
||||
|
||||
// TRICKY: since the association is specular source and target are flipped
|
||||
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
|
||||
if ( ! isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
@ -660,12 +660,12 @@ class BasicEntityPersister
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// unset the old value and set the new sql aliased value here. By definition
|
||||
// unset($identifier[$targetKeyColumn] works here with how UnitOfWork::createEntity() calls this method.
|
||||
$identifier[$this->_getSQLTableAlias($targetClass->name) . "." . $targetKeyColumn] =
|
||||
$sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
|
||||
|
||||
unset($identifier[$targetKeyColumn]);
|
||||
}
|
||||
|
||||
@ -681,7 +681,7 @@ class BasicEntityPersister
|
||||
|
||||
/**
|
||||
* Refreshes a managed entity.
|
||||
*
|
||||
*
|
||||
* @param array $id The identifier of the entity as an associative array from
|
||||
* column or field names to values.
|
||||
* @param object $entity The entity to refresh.
|
||||
@ -691,16 +691,16 @@ class BasicEntityPersister
|
||||
$sql = $this->_getSelectEntitiesSQL($id);
|
||||
list($params, $types) = $this->expandParameters($id);
|
||||
$stmt = $this->_conn->executeQuery($sql, $params, $types);
|
||||
|
||||
|
||||
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
|
||||
$hydrator->hydrateAll($stmt, $this->_rsm, array(Query::HINT_REFRESH => true));
|
||||
|
||||
if (isset($this->_class->lifecycleCallbacks[Events::postLoad])) {
|
||||
$this->_class->invokeLifecycleCallbacks(Events::postLoad, $entity);
|
||||
}
|
||||
|
||||
|
||||
$evm = $this->_em->getEventManager();
|
||||
|
||||
|
||||
if ($evm->hasListeners(Events::postLoad)) {
|
||||
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
|
||||
}
|
||||
@ -708,7 +708,7 @@ class BasicEntityPersister
|
||||
|
||||
/**
|
||||
* Loads a list of entities by a list of field criteria.
|
||||
*
|
||||
*
|
||||
* @param array $criteria
|
||||
* @param array $orderBy
|
||||
* @param int $limit
|
||||
@ -723,13 +723,13 @@ class BasicEntityPersister
|
||||
$stmt = $this->_conn->executeQuery($sql, $params, $types);
|
||||
|
||||
$hydrator = $this->_em->newHydrator(($this->_selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
|
||||
|
||||
|
||||
return $hydrator->hydrateAll($stmt, $this->_rsm, array('deferEagerLoads' => true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get (sliced or full) elements of the given collection.
|
||||
*
|
||||
*
|
||||
* @param array $assoc
|
||||
* @param object $sourceEntity
|
||||
* @param int|null $offset
|
||||
@ -739,16 +739,16 @@ class BasicEntityPersister
|
||||
public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||
{
|
||||
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity, $offset, $limit);
|
||||
|
||||
|
||||
return $this->loadArrayFromStatement($assoc, $stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an array of entities from a given dbal statement.
|
||||
*
|
||||
*
|
||||
* @param array $assoc
|
||||
* @param Doctrine\DBAL\Statement $stmt
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function loadArrayFromStatement($assoc, $stmt)
|
||||
@ -763,21 +763,21 @@ class BasicEntityPersister
|
||||
}
|
||||
|
||||
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
|
||||
|
||||
|
||||
return $hydrator->hydrateAll($stmt, $rsm, $hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrate a collection from a given dbal statement.
|
||||
*
|
||||
*
|
||||
* @param array $assoc
|
||||
* @param Doctrine\DBAL\Statement $stmt
|
||||
* @param PersistentCollection $coll
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function loadCollectionFromStatement($assoc, $stmt, $coll)
|
||||
{
|
||||
{
|
||||
$hints = array('deferEagerLoads' => true, 'collection' => $coll);
|
||||
|
||||
if (isset($assoc['indexBy'])) {
|
||||
@ -788,7 +788,7 @@ class BasicEntityPersister
|
||||
}
|
||||
|
||||
$hydrator = $this->_em->newHydrator(Query::HYDRATE_OBJECT);
|
||||
|
||||
|
||||
return $hydrator->hydrateAll($stmt, $rsm, $hints);
|
||||
}
|
||||
|
||||
@ -805,7 +805,7 @@ class BasicEntityPersister
|
||||
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
|
||||
{
|
||||
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity);
|
||||
|
||||
|
||||
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
|
||||
}
|
||||
|
||||
@ -813,15 +813,15 @@ class BasicEntityPersister
|
||||
{
|
||||
$criteria = array();
|
||||
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
|
||||
|
||||
|
||||
if ($assoc['isOwningSide']) {
|
||||
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($assoc, $this->_platform);
|
||||
|
||||
|
||||
foreach ($assoc['relationToSourceKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
|
||||
if ($sourceClass->containsForeignIdentifier) {
|
||||
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
|
||||
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
|
||||
|
||||
|
||||
if (isset($sourceClass->associationMappings[$field])) {
|
||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
$value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
|
||||
@ -839,18 +839,18 @@ class BasicEntityPersister
|
||||
} else {
|
||||
$owningAssoc = $this->_em->getClassMetadata($assoc['targetEntity'])->associationMappings[$assoc['mappedBy']];
|
||||
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($owningAssoc, $this->_platform);
|
||||
|
||||
|
||||
// TRICKY: since the association is inverted source and target are flipped
|
||||
foreach ($owningAssoc['relationToTargetKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
|
||||
if ($sourceClass->containsForeignIdentifier) {
|
||||
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
|
||||
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
|
||||
|
||||
|
||||
if (isset($sourceClass->associationMappings[$field])) {
|
||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
$value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
|
||||
}
|
||||
|
||||
|
||||
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $value;
|
||||
} else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
@ -864,7 +864,7 @@ class BasicEntityPersister
|
||||
|
||||
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, 0, $limit, $offset);
|
||||
list($params, $types) = $this->expandParameters($criteria);
|
||||
|
||||
|
||||
return $this->_conn->executeQuery($sql, $params, $types);
|
||||
}
|
||||
|
||||
@ -890,7 +890,7 @@ class BasicEntityPersister
|
||||
$orderBySql = $orderBy ? $this->_getOrderBySQL($orderBy, $this->_getSQLTableAlias($this->_class->name)) : '';
|
||||
|
||||
$lockSql = '';
|
||||
|
||||
|
||||
if ($lockMode == LockMode::PESSIMISTIC_READ) {
|
||||
$lockSql = ' ' . $this->_platform->getReadLockSql();
|
||||
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
|
||||
@ -908,7 +908,7 @@ class BasicEntityPersister
|
||||
|
||||
/**
|
||||
* Gets the ORDER BY SQL snippet for ordered collections.
|
||||
*
|
||||
*
|
||||
* @param array $orderBy
|
||||
* @param string $baseTableAlias
|
||||
* @return string
|
||||
@ -917,7 +917,7 @@ class BasicEntityPersister
|
||||
protected final function _getOrderBySQL(array $orderBy, $baseTableAlias)
|
||||
{
|
||||
$orderBySql = '';
|
||||
|
||||
|
||||
foreach ($orderBy as $fieldName => $orientation) {
|
||||
if ( ! isset($this->_class->fieldMappings[$fieldName])) {
|
||||
throw ORMException::unrecognizedField($fieldName);
|
||||
@ -928,7 +928,7 @@ class BasicEntityPersister
|
||||
: $baseTableAlias;
|
||||
|
||||
$columnName = $this->_class->getQuotedColumnName($fieldName, $this->_platform);
|
||||
|
||||
|
||||
$orderBySql .= $orderBySql ? ', ' : ' ORDER BY ';
|
||||
$orderBySql .= $tableAlias . '.' . $columnName . ' ' . $orientation;
|
||||
}
|
||||
@ -944,7 +944,7 @@ class BasicEntityPersister
|
||||
* list SQL fragment. Note that in the implementation of BasicEntityPersister
|
||||
* the resulting SQL fragment is generated only once and cached in {@link _selectColumnListSql}.
|
||||
* Subclasses may or may not do the same.
|
||||
*
|
||||
*
|
||||
* @return string The SQL fragment.
|
||||
* @todo Rename: _getSelectColumnsSQL()
|
||||
*/
|
||||
@ -961,58 +961,56 @@ class BasicEntityPersister
|
||||
// Add regular columns to select list
|
||||
foreach ($this->_class->fieldNames as $field) {
|
||||
if ($columnList) $columnList .= ', ';
|
||||
|
||||
|
||||
$columnList .= $this->_getSelectColumnSQL($field, $this->_class);
|
||||
}
|
||||
|
||||
$this->_selectJoinSql = '';
|
||||
$eagerAliasCounter = 0;
|
||||
|
||||
|
||||
foreach ($this->_class->associationMappings as $assocField => $assoc) {
|
||||
$assocColumnSQL = $this->_getSelectColumnAssociationSQL($assocField, $assoc, $this->_class);
|
||||
|
||||
|
||||
if ($assocColumnSQL) {
|
||||
if ($columnList) $columnList .= ', ';
|
||||
|
||||
|
||||
$columnList .= $assocColumnSQL;
|
||||
}
|
||||
|
||||
|
||||
if ($assoc['type'] & ClassMetadata::TO_ONE && ($assoc['fetch'] == ClassMetadata::FETCH_EAGER || !$assoc['isOwningSide'])) {
|
||||
$eagerEntity = $this->_em->getClassMetadata($assoc['targetEntity']);
|
||||
|
||||
|
||||
if ($eagerEntity->inheritanceType != ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||
continue; // now this is why you shouldn't use inheritance
|
||||
}
|
||||
|
||||
|
||||
$assocAlias = 'e' . ($eagerAliasCounter++);
|
||||
$this->_rsm->addJoinedEntityResult($assoc['targetEntity'], $assocAlias, 'r', $assocField);
|
||||
|
||||
|
||||
foreach ($eagerEntity->fieldNames AS $field) {
|
||||
if ($columnList) $columnList .= ', ';
|
||||
|
||||
|
||||
$columnList .= $this->_getSelectColumnSQL($field, $eagerEntity, $assocAlias);
|
||||
}
|
||||
|
||||
|
||||
foreach ($eagerEntity->associationMappings as $assoc2Field => $assoc2) {
|
||||
$assoc2ColumnSQL = $this->_getSelectColumnAssociationSQL($assoc2Field, $assoc2, $eagerEntity, $assocAlias);
|
||||
|
||||
|
||||
if ($assoc2ColumnSQL) {
|
||||
if ($columnList) $columnList .= ', ';
|
||||
$columnList .= $assoc2ColumnSQL;
|
||||
}
|
||||
}
|
||||
|
||||
$first = true;
|
||||
|
||||
|
||||
if ($assoc['isOwningSide']) {
|
||||
$this->_selectJoinSql .= ' ' . $this->getJoinSQLForJoinColumns($assoc['joinColumns']);
|
||||
$this->_selectJoinSql .= ' ' . $eagerEntity->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($eagerEntity->name, $assocAlias) .' ON ';
|
||||
|
||||
|
||||
foreach ($assoc['sourceToTargetKeyColumns'] AS $sourceCol => $targetCol) {
|
||||
if ( ! $first) {
|
||||
$this->_selectJoinSql .= ' AND ';
|
||||
}
|
||||
|
||||
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
|
||||
. $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.' . $targetCol;
|
||||
$first = false;
|
||||
@ -1029,8 +1027,8 @@ class BasicEntityPersister
|
||||
if ( ! $first) {
|
||||
$this->_selectJoinSql .= ' AND ';
|
||||
}
|
||||
|
||||
$this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = '
|
||||
|
||||
$this->_selectJoinSql .= $this->_getSQLTableAlias($owningAssoc['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = '
|
||||
. $this->_getSQLTableAlias($owningAssoc['targetEntity']) . '.' . $targetCol;
|
||||
$first = false;
|
||||
}
|
||||
@ -1042,33 +1040,32 @@ class BasicEntityPersister
|
||||
|
||||
return $this->_selectColumnListSql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the SQL join fragment used when selecting entities from an association.
|
||||
*
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $assoc
|
||||
* @param ClassMetadata $class
|
||||
* @param string $alias
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _getSelectColumnAssociationSQL($field, $assoc, ClassMetadata $class, $alias = 'r')
|
||||
{
|
||||
$columnList = '';
|
||||
|
||||
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
if ($columnList) $columnList .= ', ';
|
||||
|
||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
||||
$resultColumnName = $this->getSQLColumnAlias($srcColumn);
|
||||
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
|
||||
. '.' . $srcColumn . ' AS ' . $resultColumnName;
|
||||
$this->_rsm->addMetaResult($alias, $resultColumnName, $srcColumn, isset($assoc['id']) && $assoc['id'] === true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $columnList;
|
||||
}
|
||||
|
||||
@ -1088,10 +1085,10 @@ class BasicEntityPersister
|
||||
$owningAssoc = $this->_em->getClassMetadata($manyToMany['targetEntity'])->associationMappings[$manyToMany['mappedBy']];
|
||||
$joinClauses = $owningAssoc['relationToSourceKeyColumns'];
|
||||
}
|
||||
|
||||
|
||||
$joinTableName = $this->_class->getQuotedJoinTableName($owningAssoc, $this->_platform);
|
||||
$joinSql = '';
|
||||
|
||||
|
||||
foreach ($joinClauses as $joinTableColumn => $sourceColumn) {
|
||||
if ($joinSql != '') $joinSql .= ' AND ';
|
||||
|
||||
@ -1110,7 +1107,7 @@ class BasicEntityPersister
|
||||
|
||||
/**
|
||||
* Gets the INSERT SQL used by the persister to persist a new entity.
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _getInsertSQL()
|
||||
@ -1118,7 +1115,7 @@ class BasicEntityPersister
|
||||
if ($this->_insertSql === null) {
|
||||
$insertSql = '';
|
||||
$columns = $this->_getInsertColumnList();
|
||||
|
||||
|
||||
if (empty($columns)) {
|
||||
$insertSql = $this->_platform->getEmptyIdentityInsertSQL(
|
||||
$this->_class->getQuotedTableName($this->_platform),
|
||||
@ -1131,10 +1128,10 @@ class BasicEntityPersister
|
||||
$insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform)
|
||||
. ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', $values) . ')';
|
||||
}
|
||||
|
||||
|
||||
$this->_insertSql = $insertSql;
|
||||
}
|
||||
|
||||
|
||||
return $this->_insertSql;
|
||||
}
|
||||
|
||||
@ -1149,15 +1146,15 @@ class BasicEntityPersister
|
||||
protected function _getInsertColumnList()
|
||||
{
|
||||
$columns = array();
|
||||
|
||||
|
||||
foreach ($this->_class->reflFields as $name => $field) {
|
||||
if ($this->_class->isVersioned && $this->_class->versionField == $name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (isset($this->_class->associationMappings[$name])) {
|
||||
$assoc = $this->_class->associationMappings[$name];
|
||||
|
||||
|
||||
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
|
||||
foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) {
|
||||
$columns[] = $sourceCol;
|
||||
@ -1181,11 +1178,10 @@ class BasicEntityPersister
|
||||
*/
|
||||
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
|
||||
{
|
||||
$columnName = $class->columnNames[$field];
|
||||
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
|
||||
. '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
|
||||
|
||||
$columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
|
||||
|
||||
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
|
||||
|
||||
return $sql . ' AS ' . $columnAlias;
|
||||
@ -1193,7 +1189,7 @@ class BasicEntityPersister
|
||||
|
||||
/**
|
||||
* Gets the SQL table alias for the given class name.
|
||||
*
|
||||
*
|
||||
* @param string $className
|
||||
* @return string The SQL table alias.
|
||||
* @todo Reconsider. Binding table aliases to class names is not such a good idea.
|
||||
@ -1203,15 +1199,15 @@ class BasicEntityPersister
|
||||
if ($assocName) {
|
||||
$className .= '#' . $assocName;
|
||||
}
|
||||
|
||||
|
||||
if (isset($this->_sqlTableAliases[$className])) {
|
||||
return $this->_sqlTableAliases[$className];
|
||||
}
|
||||
|
||||
|
||||
$tableAlias = 't' . $this->_sqlAliasCounter++;
|
||||
|
||||
$this->_sqlTableAliases[$className] = $tableAlias;
|
||||
|
||||
|
||||
return $tableAlias;
|
||||
}
|
||||
|
||||
@ -1235,9 +1231,9 @@ class BasicEntityPersister
|
||||
$sql = 'SELECT 1 '
|
||||
. $this->_platform->appendLockHint($this->getLockTablesSql(), $lockMode)
|
||||
. ($conditionSql ? ' WHERE ' . $conditionSql : '') . ' ' . $lockSql;
|
||||
|
||||
|
||||
list($params, $types) = $this->expandParameters($criteria);
|
||||
|
||||
|
||||
$stmt = $this->_conn->executeQuery($sql, $params, $types);
|
||||
}
|
||||
|
||||
@ -1266,25 +1262,25 @@ class BasicEntityPersister
|
||||
protected function _getSelectConditionSQL(array $criteria, $assoc = null)
|
||||
{
|
||||
$conditionSql = '';
|
||||
|
||||
|
||||
foreach ($criteria as $field => $value) {
|
||||
$conditionSql .= $conditionSql ? ' AND ' : '';
|
||||
|
||||
if (isset($this->_class->columnNames[$field])) {
|
||||
$className = (isset($this->_class->fieldMappings[$field]['inherited']))
|
||||
? $this->_class->fieldMappings[$field]['inherited']
|
||||
? $this->_class->fieldMappings[$field]['inherited']
|
||||
: $this->_class->name;
|
||||
|
||||
|
||||
$conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->getQuotedColumnName($field, $this->_platform);
|
||||
} else if (isset($this->_class->associationMappings[$field])) {
|
||||
if ( ! $this->_class->associationMappings[$field]['isOwningSide']) {
|
||||
throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field);
|
||||
}
|
||||
|
||||
|
||||
$className = (isset($this->_class->associationMappings[$field]['inherited']))
|
||||
? $this->_class->associationMappings[$field]['inherited']
|
||||
: $this->_class->name;
|
||||
|
||||
|
||||
$conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
|
||||
} else if ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false) {
|
||||
// very careless developers could potentially open up this normally hidden api for userland attacks,
|
||||
@ -1295,7 +1291,7 @@ class BasicEntityPersister
|
||||
} else {
|
||||
throw ORMException::unrecognizedField($field);
|
||||
}
|
||||
|
||||
|
||||
$conditionSql .= (is_array($value)) ? ' IN (?)' : (($value === null) ? ' IS NULL' : ' = ?');
|
||||
}
|
||||
return $conditionSql;
|
||||
@ -1313,7 +1309,7 @@ class BasicEntityPersister
|
||||
public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||
{
|
||||
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity, $offset, $limit);
|
||||
|
||||
|
||||
return $this->loadArrayFromStatement($assoc, $stmt);
|
||||
}
|
||||
|
||||
@ -1329,7 +1325,7 @@ class BasicEntityPersister
|
||||
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
|
||||
{
|
||||
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity);
|
||||
|
||||
|
||||
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
|
||||
}
|
||||
|
||||
@ -1354,12 +1350,12 @@ class BasicEntityPersister
|
||||
if ($sourceClass->containsForeignIdentifier) {
|
||||
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
|
||||
$value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
|
||||
|
||||
|
||||
if (isset($sourceClass->associationMappings[$field])) {
|
||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
$value = $value[$this->_em->getClassMetadata($sourceClass->associationMappings[$field]['targetEntity'])->identifier[0]];
|
||||
}
|
||||
|
||||
|
||||
$criteria[$tableAlias . "." . $targetKeyColumn] = $value;
|
||||
} else {
|
||||
$criteria[$tableAlias . "." . $targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
@ -1390,13 +1386,13 @@ class BasicEntityPersister
|
||||
$types[] = $this->getType($field, $value);
|
||||
$params[] = $this->getValue($value);
|
||||
}
|
||||
|
||||
|
||||
return array($params, $types);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Infer field type to be used by parameter type casting.
|
||||
*
|
||||
*
|
||||
* @param string $field
|
||||
* @param mixed $value
|
||||
* @return integer
|
||||
@ -1410,11 +1406,11 @@ class BasicEntityPersister
|
||||
|
||||
case (isset($this->_class->associationMappings[$field])):
|
||||
$assoc = $this->_class->associationMappings[$field];
|
||||
|
||||
|
||||
if (count($assoc['sourceToTargetKeyColumns']) > 1) {
|
||||
throw Query\QueryException::associationPathCompositeKeyNotSupported();
|
||||
}
|
||||
|
||||
|
||||
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
|
||||
$targetColumn = $assoc['joinColumns'][0]['referencedColumnName'];
|
||||
$type = null;
|
||||
@ -1432,36 +1428,36 @@ class BasicEntityPersister
|
||||
if (is_array($value)) {
|
||||
$type += Connection::ARRAY_PARAM_OFFSET;
|
||||
}
|
||||
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve parameter value
|
||||
*
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
* @return mixed
|
||||
*/
|
||||
private function getValue($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$newValue = array();
|
||||
|
||||
|
||||
foreach ($value as $itemValue) {
|
||||
$newValue[] = $this->getIndividualValue($itemValue);
|
||||
}
|
||||
|
||||
|
||||
return $newValue;
|
||||
}
|
||||
|
||||
|
||||
return $this->getIndividualValue($value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve an invidiual parameter value
|
||||
*
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
* @return mixed
|
||||
*/
|
||||
private function getIndividualValue($value)
|
||||
{
|
||||
@ -1472,11 +1468,11 @@ class BasicEntityPersister
|
||||
$class = $this->_em->getClassMetadata(get_class($value));
|
||||
$idValues = $class->getIdentifierValues($value);
|
||||
}
|
||||
|
||||
|
||||
$value = $idValues[key($idValues)];
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1488,17 +1484,17 @@ class BasicEntityPersister
|
||||
public function exists($entity, array $extraConditions = array())
|
||||
{
|
||||
$criteria = $this->_class->getIdentifierValues($entity);
|
||||
|
||||
|
||||
if ($extraConditions) {
|
||||
$criteria = array_merge($criteria, $extraConditions);
|
||||
}
|
||||
|
||||
$sql = 'SELECT 1'
|
||||
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($this->_class->name)
|
||||
$sql = 'SELECT 1 '
|
||||
. $this->getLockTablesSql()
|
||||
. ' WHERE ' . $this->_getSelectConditionSQL($criteria);
|
||||
|
||||
|
||||
list($params, $types) = $this->expandParameters($criteria);
|
||||
|
||||
|
||||
return (bool) $this->_conn->fetchColumn($sql, $params);
|
||||
}
|
||||
|
||||
@ -1519,4 +1515,19 @@ class BasicEntityPersister
|
||||
|
||||
return 'INNER JOIN';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an SQL column alias for a column name.
|
||||
*
|
||||
* @param string $columnName
|
||||
* @return string
|
||||
*/
|
||||
public function getSQLColumnAlias($columnName)
|
||||
{
|
||||
// Trim the column alias to the maximum identifier length of the platform.
|
||||
// If the alias is to long, characters are cut off from the beginning.
|
||||
return $this->_platform->getSQLResultCasing(
|
||||
substr($columnName . $this->_sqlAliasCounter++, -$this->_platform->getMaxIdentifierLength())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
/**
|
||||
* Map of table to quoted table names.
|
||||
*
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_quotedTableMap = array();
|
||||
@ -59,7 +59,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$class = ($this->_class->name !== $this->_class->rootEntityName)
|
||||
? $this->_em->getClassMetadata($this->_class->rootEntityName)
|
||||
: $this->_class;
|
||||
|
||||
|
||||
return $class->getTableName();
|
||||
}
|
||||
|
||||
@ -73,10 +73,10 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
{
|
||||
if (isset($this->_class->fieldMappings[$this->_class->versionField]['inherited'])) {
|
||||
$definingClassName = $this->_class->fieldMappings[$this->_class->versionField]['inherited'];
|
||||
|
||||
|
||||
return $this->_em->getClassMetadata($definingClassName);
|
||||
}
|
||||
|
||||
|
||||
return $this->_class;
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
if (isset($this->_owningTableMap[$fieldName])) {
|
||||
return $this->_owningTableMap[$fieldName];
|
||||
}
|
||||
|
||||
|
||||
if (isset($this->_class->associationMappings[$fieldName]['inherited'])) {
|
||||
$cm = $this->_em->getClassMetadata($this->_class->associationMappings[$fieldName]['inherited']);
|
||||
} else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) {
|
||||
@ -130,15 +130,15 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// Prepare statements for sub tables.
|
||||
$subTableStmts = array();
|
||||
|
||||
|
||||
if ($rootClass !== $this->_class) {
|
||||
$subTableStmts[$this->_class->getTableName()] = $this->_conn->prepare($this->_getInsertSQL());
|
||||
}
|
||||
|
||||
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$parentTableName = $parentClass->getTableName();
|
||||
|
||||
|
||||
if ($parentClass !== $rootClass) {
|
||||
$parentPersister = $this->_em->getUnitOfWork()->getEntityPersister($parentClassName);
|
||||
$subTableStmts[$parentTableName] = $this->_conn->prepare($parentPersister->_getInsertSQL());
|
||||
@ -153,11 +153,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// Execute insert on root table
|
||||
$paramIndex = 1;
|
||||
|
||||
|
||||
foreach ($insertData[$rootTableName] as $columnName => $value) {
|
||||
$rootTableStmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]);
|
||||
}
|
||||
|
||||
|
||||
$rootTableStmt->execute();
|
||||
|
||||
if ($isPostInsertId) {
|
||||
@ -172,23 +172,23 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
foreach ($subTableStmts as $tableName => $stmt) {
|
||||
$data = isset($insertData[$tableName]) ? $insertData[$tableName] : array();
|
||||
$paramIndex = 1;
|
||||
|
||||
|
||||
foreach ((array) $id as $idName => $idVal) {
|
||||
$type = isset($this->_columnTypes[$idName]) ? $this->_columnTypes[$idName] : Type::STRING;
|
||||
|
||||
|
||||
$stmt->bindValue($paramIndex++, $idVal, $type);
|
||||
}
|
||||
|
||||
|
||||
foreach ($data as $columnName => $value) {
|
||||
$stmt->bindValue($paramIndex++, $value, $this->_columnTypes[$columnName]);
|
||||
}
|
||||
|
||||
|
||||
$stmt->execute();
|
||||
}
|
||||
}
|
||||
|
||||
$rootTableStmt->closeCursor();
|
||||
|
||||
|
||||
foreach ($subTableStmts as $stmt) {
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
@ -220,7 +220,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$entity, $this->_quotedTableMap[$tableName], $data, $isVersioned && $versionedTable == $tableName
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Make sure the table with the version column is updated even if no columns on that
|
||||
// table were affected.
|
||||
if ($isVersioned && ! isset($updateData[$versionedTable])) {
|
||||
@ -251,7 +251,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
} else {
|
||||
// Delete from all tables individually, starting from this class' table up to the root table.
|
||||
$this->_conn->delete($this->_class->getQuotedTableName($this->_platform), $id);
|
||||
|
||||
|
||||
foreach ($this->_class->parentClasses as $parentClass) {
|
||||
$this->_conn->delete(
|
||||
$this->_em->getClassMetadata($parentClass)->getQuotedTableName($this->_platform), $id
|
||||
@ -270,16 +270,16 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// Create the column list fragment only once
|
||||
if ($this->_selectColumnListSql === null) {
|
||||
|
||||
|
||||
$this->_rsm = new ResultSetMapping();
|
||||
$this->_rsm->addEntityResult($this->_class->name, 'r');
|
||||
|
||||
|
||||
// Add regular columns
|
||||
$columnList = '';
|
||||
|
||||
|
||||
foreach ($this->_class->fieldMappings as $fieldName => $mapping) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
|
||||
|
||||
$columnList .= $this->_getSelectColumnSQL(
|
||||
$fieldName,
|
||||
isset($mapping['inherited']) ? $this->_em->getClassMetadata($mapping['inherited']) : $this->_class
|
||||
@ -290,12 +290,12 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
foreach ($this->_class->associationMappings as $assoc2) {
|
||||
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE) {
|
||||
$tableAlias = isset($assoc2['inherited']) ? $this->_getSQLTableAlias($assoc2['inherited']) : $baseTableAlias;
|
||||
|
||||
|
||||
foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
|
||||
|
||||
$columnList .= $this->getSelectJoinColumnSQL(
|
||||
$tableAlias,
|
||||
$tableAlias,
|
||||
$srcColumn,
|
||||
isset($assoc2['inherited']) ? $assoc2['inherited'] : $this->_class->name
|
||||
);
|
||||
@ -309,23 +309,23 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
$columnList .= ', ' . $tableAlias . '.' . $discrColumn;
|
||||
|
||||
$resultColumnName = $this->_platform->getSQLResultCasing($discrColumn);
|
||||
|
||||
|
||||
$this->_rsm->setDiscriminatorColumn('r', $resultColumnName);
|
||||
$this->_rsm->addMetaResult('r', $resultColumnName, $discrColumn);
|
||||
}
|
||||
|
||||
// INNER JOIN parent tables
|
||||
$joinSql = '';
|
||||
|
||||
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$tableAlias = $this->_getSQLTableAlias($parentClassName);
|
||||
$joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
|
||||
|
||||
foreach ($idColumns as $idColumn) {
|
||||
if ($first) $first = false; else $joinSql .= ' AND ';
|
||||
|
||||
|
||||
$joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
|
||||
}
|
||||
}
|
||||
@ -339,7 +339,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
// Add subclass columns
|
||||
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
|
||||
if (isset($mapping['inherited'])) continue;
|
||||
|
||||
|
||||
$columnList .= ', ' . $this->_getSelectColumnSQL($fieldName, $subClass);
|
||||
}
|
||||
|
||||
@ -348,9 +348,9 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE && ! isset($assoc2['inherited'])) {
|
||||
foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) {
|
||||
if ($columnList != '') $columnList .= ', ';
|
||||
|
||||
|
||||
$columnList .= $this->getSelectJoinColumnSQL(
|
||||
$tableAlias,
|
||||
$tableAlias,
|
||||
$srcColumn,
|
||||
isset($assoc2['inherited']) ? $assoc2['inherited'] : $subClass->name
|
||||
);
|
||||
@ -362,10 +362,10 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
// Add LEFT JOIN
|
||||
$joinSql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
|
||||
|
||||
foreach ($idColumns as $idColumn) {
|
||||
if ($first) $first = false; else $joinSql .= ' AND ';
|
||||
|
||||
|
||||
$joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
|
||||
}
|
||||
}
|
||||
@ -382,7 +382,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
|
||||
$lockSql = '';
|
||||
|
||||
|
||||
if ($lockMode == LockMode::PESSIMISTIC_READ) {
|
||||
$lockSql = ' ' . $this->_platform->getReadLockSql();
|
||||
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
|
||||
@ -408,29 +408,29 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// INNER JOIN parent tables
|
||||
$joinSql = '';
|
||||
|
||||
|
||||
foreach ($this->_class->parentClasses as $parentClassName) {
|
||||
$parentClass = $this->_em->getClassMetadata($parentClassName);
|
||||
$tableAlias = $this->_getSQLTableAlias($parentClassName);
|
||||
$joinSql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||
$first = true;
|
||||
|
||||
|
||||
foreach ($idColumns as $idColumn) {
|
||||
if ($first) $first = false; else $joinSql .= ' AND ';
|
||||
|
||||
|
||||
$joinSql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
|
||||
}
|
||||
}
|
||||
|
||||
return 'FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $baseTableAlias . $joinSql;
|
||||
}
|
||||
|
||||
|
||||
/* Ensure this method is never called. This persister overrides _getSelectEntitiesSQL directly. */
|
||||
protected function _getSelectColumnListSQL()
|
||||
{
|
||||
throw new \BadMethodCallException("Illegal invocation of ".__METHOD__.".");
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function _getInsertColumnList()
|
||||
{
|
||||
|
@ -232,6 +232,9 @@ final class Query extends AbstractQuery
|
||||
protected function _doExecute()
|
||||
{
|
||||
$executor = $this->_parse()->getSqlExecutor();
|
||||
if ($this->_queryCacheProfile) {
|
||||
$executor->setQueryCacheProfile($this->_queryCacheProfile);
|
||||
}
|
||||
|
||||
// Prepare parameters
|
||||
$paramMappings = $this->_parserResult->getParameterMappings();
|
||||
@ -523,7 +526,7 @@ final class Query extends AbstractQuery
|
||||
*
|
||||
* @param array $params The query parameters.
|
||||
* @param integer $hydrationMode The hydration mode to use.
|
||||
* @return IterableResult
|
||||
* @return \Doctrine\ORM\Internal\Hydration\IterableResult
|
||||
*/
|
||||
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
|
||||
{
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -22,6 +20,7 @@
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||
|
||||
/**
|
||||
* Base class for SQL statement executors.
|
||||
@ -34,8 +33,16 @@ use Doctrine\DBAL\Connection;
|
||||
*/
|
||||
abstract class AbstractSqlExecutor
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $_sqlStatements;
|
||||
|
||||
/**
|
||||
* @var QueryCacheProfile
|
||||
*/
|
||||
protected $queryCacheProfile;
|
||||
|
||||
/**
|
||||
* Gets the SQL statements that are executed by the executor.
|
||||
*
|
||||
@ -46,12 +53,18 @@ abstract class AbstractSqlExecutor
|
||||
return $this->_sqlStatements;
|
||||
}
|
||||
|
||||
public function setQueryCacheProfile(QueryCacheProfile $qcp)
|
||||
{
|
||||
$this->queryCacheProfile = $qcp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all sql statements.
|
||||
*
|
||||
* @param Doctrine\DBAL\Connection $conn The database connection that is used to execute the queries.
|
||||
* @param array $params The parameters.
|
||||
* @param array $types The parameter types.
|
||||
* @return Doctrine\DBAL\Driver\Statement
|
||||
*/
|
||||
abstract public function execute(Connection $conn, array $params, array $types);
|
||||
abstract public function execute(Connection $conn, array $params, array $types);
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -32,7 +30,6 @@ use Doctrine\DBAL\Connection,
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
||||
{
|
||||
@ -102,11 +99,7 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all SQL statements.
|
||||
*
|
||||
* @param Doctrine\DBAL\Connection $conn The database connection that is used to execute the queries.
|
||||
* @param array $params The parameters.
|
||||
* @override
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function execute(Connection $conn, array $params, array $types)
|
||||
{
|
||||
|
@ -141,11 +141,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all SQL statements.
|
||||
*
|
||||
* @param Connection $conn The database connection that is used to execute the queries.
|
||||
* @param array $params The parameters.
|
||||
* @override
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function execute(Connection $conn, array $params, array $types)
|
||||
{
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -30,7 +28,6 @@ use Doctrine\DBAL\Connection,
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @version $Revision$
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
*/
|
||||
@ -41,8 +38,11 @@ class SingleSelectExecutor extends AbstractSqlExecutor
|
||||
$this->_sqlStatements = $sqlWalker->walkSelectStatement($AST);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function execute(Connection $conn, array $params, array $types)
|
||||
{
|
||||
return $conn->executeQuery($this->_sqlStatements, $params, $types);
|
||||
return $conn->executeQuery($this->_sqlStatements, $params, $types, $this->queryCacheProfile);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -30,7 +28,6 @@ use Doctrine\DBAL\Connection,
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @version $Revision$
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor.
|
||||
@ -45,7 +42,10 @@ class SingleTableDeleteUpdateExecutor extends AbstractSqlExecutor
|
||||
$this->_sqlStatements = $sqlWalker->walkDeleteStatement($AST);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function execute(Connection $conn, array $params, array $types)
|
||||
{
|
||||
return $conn->executeUpdate($this->_sqlStatements, $params, $types);
|
||||
|
@ -57,7 +57,7 @@ abstract class Base
|
||||
|
||||
public function add($arg)
|
||||
{
|
||||
if ( $arg !== null ) {
|
||||
if ( $arg !== null || ($arg instanceof self && $arg->count() > 0) ) {
|
||||
// If we decide to keep Expr\Base instances, we can use this check
|
||||
if ( ! is_string($arg)) {
|
||||
$class = get_class($arg);
|
||||
|
@ -86,20 +86,22 @@ class ResultSetMappingBuilder extends ResultSetMapping
|
||||
if (isset($renamedColumns[$columnName])) {
|
||||
$columnName = $renamedColumns[$columnName];
|
||||
}
|
||||
$columnName = $platform->getSQLResultCasing($columnName);
|
||||
if (isset($this->fieldMappings[$columnName])) {
|
||||
throw new \InvalidArgumentException("The column '$columnName' conflicts with another column in the mapper.");
|
||||
}
|
||||
$this->addFieldResult($alias, $platform->getSQLResultCasing($columnName), $propertyName);
|
||||
$this->addFieldResult($alias, $columnName, $propertyName);
|
||||
}
|
||||
foreach ($classMetadata->associationMappings AS $associationMapping) {
|
||||
if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
|
||||
foreach ($associationMapping['joinColumns'] AS $joinColumn) {
|
||||
$columnName = $joinColumn['name'];
|
||||
$renamedColumnName = isset($renamedColumns[$columnName]) ? $renamedColumns[$columnName] : $columnName;
|
||||
$renamedColumnName = $platform->getSQLResultCasing($renamedColumnName);
|
||||
if (isset($this->metaMappings[$renamedColumnName])) {
|
||||
throw new \InvalidArgumentException("The column '$renamedColumnName' conflicts with another column in the mapper.");
|
||||
}
|
||||
$this->addMetaResult($alias, $platform->getSQLResultCasing($renamedColumnName), $platform->getSQLResultCasing($columnName));
|
||||
$this->addMetaResult($alias, $renamedColumnName, $columnName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -67,7 +67,9 @@ class SchemaTool
|
||||
/**
|
||||
* Creates the database schema for the given array of ClassMetadata instances.
|
||||
*
|
||||
* @throws ToolsException
|
||||
* @param array $classes
|
||||
* @return void
|
||||
*/
|
||||
public function createSchema(array $classes)
|
||||
{
|
||||
@ -75,7 +77,11 @@ class SchemaTool
|
||||
$conn = $this->_em->getConnection();
|
||||
|
||||
foreach ($createSchemaSql as $sql) {
|
||||
$conn->executeQuery($sql);
|
||||
try {
|
||||
$conn->executeQuery($sql);
|
||||
} catch(\Exception $e) {
|
||||
throw ToolsException::schemaToolFailure($sql, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,7 +100,7 @@ class SchemaTool
|
||||
|
||||
/**
|
||||
* Some instances of ClassMetadata don't need to be processed in the SchemaTool context. This method detects them.
|
||||
*
|
||||
*
|
||||
* @param ClassMetadata $class
|
||||
* @param array $processedClasses
|
||||
* @return bool
|
||||
@ -551,7 +557,7 @@ class SchemaTool
|
||||
try {
|
||||
$conn->executeQuery($sql);
|
||||
} catch(\Exception $e) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -589,7 +595,7 @@ class SchemaTool
|
||||
|
||||
/**
|
||||
* Get SQL to drop the tables defined by the passed classes.
|
||||
*
|
||||
*
|
||||
* @param array $classes
|
||||
* @return array
|
||||
*/
|
||||
@ -615,7 +621,7 @@ class SchemaTool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($this->_platform->supportsSequences()) {
|
||||
foreach ($schema->getSequences() AS $sequence) {
|
||||
$visitor->acceptSequence($sequence);
|
||||
@ -659,7 +665,7 @@ class SchemaTool
|
||||
/**
|
||||
* Gets the sequence of SQL statements that need to be performed in order
|
||||
* to bring the given class mappings in-synch with the relational schema.
|
||||
* If $saveMode is set to true the command is executed in the Database,
|
||||
* If $saveMode is set to true the command is executed in the Database,
|
||||
* else SQL is returned.
|
||||
*
|
||||
* @param array $classes The classes to consider.
|
||||
|
@ -50,7 +50,7 @@ class SchemaValidator
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the internal consistency of mapping files.
|
||||
* Checks the internal consistency of all mapping files.
|
||||
*
|
||||
* There are several checks that can't be done at runtime or are too expensive, which can be verified
|
||||
* with this command. For example:
|
||||
@ -69,150 +69,7 @@ class SchemaValidator
|
||||
$classes = $cmf->getAllMetadata();
|
||||
|
||||
foreach ($classes AS $class) {
|
||||
$ce = array();
|
||||
/* @var $class ClassMetadata */
|
||||
foreach ($class->associationMappings AS $fieldName => $assoc) {
|
||||
if (!$cmf->hasMetadataFor($assoc['targetEntity'])) {
|
||||
$ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown.';
|
||||
}
|
||||
|
||||
if ($assoc['mappedBy'] && $assoc['inversedBy']) {
|
||||
$ce[] = "The association " . $class . "#" . $fieldName . " cannot be defined as both inverse and owning.";
|
||||
}
|
||||
|
||||
$targetMetadata = $cmf->getMetadataFor($assoc['targetEntity']);
|
||||
|
||||
/* @var $assoc AssociationMapping */
|
||||
if ($assoc['mappedBy']) {
|
||||
if ($targetMetadata->hasField($assoc['mappedBy'])) {
|
||||
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
|
||||
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which is not defined as association.";
|
||||
}
|
||||
if (!$targetMetadata->hasAssociation($assoc['mappedBy'])) {
|
||||
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
|
||||
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which does not exist.";
|
||||
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] == null) {
|
||||
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the inverse side of a ".
|
||||
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
|
||||
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
|
||||
"'inversedBy' attribute.";
|
||||
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] != $fieldName) {
|
||||
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
|
||||
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " are ".
|
||||
"incosistent with each other.";
|
||||
}
|
||||
}
|
||||
|
||||
if ($assoc['inversedBy']) {
|
||||
if ($targetMetadata->hasField($assoc['inversedBy'])) {
|
||||
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ".
|
||||
"field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which is not defined as association.";
|
||||
}
|
||||
if (!$targetMetadata->hasAssociation($assoc['inversedBy'])) {
|
||||
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ".
|
||||
"field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which does not exist.";
|
||||
} else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] == null) {
|
||||
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the owning side of a ".
|
||||
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
|
||||
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
|
||||
"'inversedBy' attribute.";
|
||||
} else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] != $fieldName) {
|
||||
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
|
||||
$assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " are ".
|
||||
"incosistent with each other.";
|
||||
}
|
||||
}
|
||||
|
||||
if ($assoc['isOwningSide']) {
|
||||
if ($assoc['type'] == ClassMetadataInfo::MANY_TO_MANY) {
|
||||
foreach ($assoc['joinTable']['joinColumns'] AS $joinColumn) {
|
||||
if (!isset($class->fieldNames[$joinColumn['referencedColumnName']])) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
|
||||
"have a corresponding field with this column name on the class '" . $class->name . "'.";
|
||||
break;
|
||||
}
|
||||
|
||||
$fieldName = $class->fieldNames[$joinColumn['referencedColumnName']];
|
||||
if (!in_array($fieldName, $class->identifier)) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
|
||||
"has to be a primary key column.";
|
||||
}
|
||||
}
|
||||
foreach ($assoc['joinTable']['inverseJoinColumns'] AS $inverseJoinColumn) {
|
||||
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']);
|
||||
if (!isset($targetClass->fieldNames[$inverseJoinColumn['referencedColumnName']])) {
|
||||
$ce[] = "The inverse referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' does not " .
|
||||
"have a corresponding field with this column name on the class '" . $targetClass->name . "'.";
|
||||
break;
|
||||
}
|
||||
|
||||
$fieldName = $targetClass->fieldNames[$inverseJoinColumn['referencedColumnName']];
|
||||
if (!in_array($fieldName, $targetClass->identifier)) {
|
||||
$ce[] = "The referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' " .
|
||||
"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']);
|
||||
if (!isset($targetClass->fieldNames[$joinColumn['referencedColumnName']])) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
|
||||
"have a corresponding field with this column name on the class '" . $targetClass->name . "'.";
|
||||
break;
|
||||
}
|
||||
|
||||
$fieldName = $targetClass->fieldNames[$joinColumn['referencedColumnName']];
|
||||
if (!in_array($fieldName, $targetClass->identifier)) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
|
||||
"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 . "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($assoc['orderBy']) && $assoc['orderBy'] !== null) {
|
||||
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']);
|
||||
foreach ($assoc['orderBy'] AS $orderField => $orientation) {
|
||||
if (!$targetClass->hasField($orderField)) {
|
||||
$ce[] = "The association " . $class->name."#".$fieldName." is ordered by a foreign field " .
|
||||
$orderField . " that is not a field on the target entity " . $targetClass->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($class->reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $publicAttr) {
|
||||
if ($publicAttr->isStatic()) {
|
||||
continue;
|
||||
}
|
||||
$ce[] = "Field '".$publicAttr->getName()."' in class '".$class->name."' must be private ".
|
||||
"or protected. Public fields may break lazy-loading.";
|
||||
}
|
||||
|
||||
foreach ($class->subClasses AS $subClass) {
|
||||
if (!in_array($class->name, class_parents($subClass))) {
|
||||
$ce[] = "According to the discriminator map class '" . $subClass . "' has to be a child ".
|
||||
"of '" . $class->name . "' but these entities are not related through inheritance.";
|
||||
}
|
||||
}
|
||||
|
||||
if ($ce) {
|
||||
if ($ce = $this->validateClass($class)) {
|
||||
$errors[$class->name] = $ce;
|
||||
}
|
||||
}
|
||||
@ -220,6 +77,165 @@ class SchemaValidator
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a single class of the current
|
||||
*
|
||||
* @param ClassMetadataInfo $class
|
||||
* @return array
|
||||
*/
|
||||
public function validateClass(ClassMetadataInfo $class)
|
||||
{
|
||||
$ce = array();
|
||||
$cmf = $this->em->getMetadataFactory();
|
||||
|
||||
foreach ($class->associationMappings AS $fieldName => $assoc) {
|
||||
if (!$cmf->hasMetadataFor($assoc['targetEntity'])) {
|
||||
$ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown.';
|
||||
return $ce;
|
||||
}
|
||||
|
||||
if ($assoc['mappedBy'] && $assoc['inversedBy']) {
|
||||
$ce[] = "The association " . $class . "#" . $fieldName . " cannot be defined as both inverse and owning.";
|
||||
}
|
||||
|
||||
$targetMetadata = $cmf->getMetadataFor($assoc['targetEntity']);
|
||||
|
||||
/* @var $assoc AssociationMapping */
|
||||
if ($assoc['mappedBy']) {
|
||||
if ($targetMetadata->hasField($assoc['mappedBy'])) {
|
||||
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
|
||||
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which is not defined as association.";
|
||||
}
|
||||
if (!$targetMetadata->hasAssociation($assoc['mappedBy'])) {
|
||||
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
|
||||
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which does not exist.";
|
||||
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] == null) {
|
||||
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the inverse side of a ".
|
||||
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
|
||||
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
|
||||
"'inversedBy' attribute.";
|
||||
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] != $fieldName) {
|
||||
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
|
||||
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " are ".
|
||||
"incosistent with each other.";
|
||||
}
|
||||
}
|
||||
|
||||
if ($assoc['inversedBy']) {
|
||||
if ($targetMetadata->hasField($assoc['inversedBy'])) {
|
||||
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ".
|
||||
"field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which is not defined as association.";
|
||||
}
|
||||
if (!$targetMetadata->hasAssociation($assoc['inversedBy'])) {
|
||||
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ".
|
||||
"field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which does not exist.";
|
||||
} else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] == null) {
|
||||
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the owning side of a ".
|
||||
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
|
||||
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
|
||||
"'inversedBy' attribute.";
|
||||
} else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] != $fieldName) {
|
||||
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
|
||||
$assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " are ".
|
||||
"incosistent with each other.";
|
||||
}
|
||||
}
|
||||
|
||||
if ($assoc['isOwningSide']) {
|
||||
if ($assoc['type'] == ClassMetadataInfo::MANY_TO_MANY) {
|
||||
foreach ($assoc['joinTable']['joinColumns'] AS $joinColumn) {
|
||||
if (!isset($class->fieldNames[$joinColumn['referencedColumnName']])) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
|
||||
"have a corresponding field with this column name on the class '" . $class->name . "'.";
|
||||
break;
|
||||
}
|
||||
|
||||
$fieldName = $class->fieldNames[$joinColumn['referencedColumnName']];
|
||||
if (!in_array($fieldName, $class->identifier)) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
|
||||
"has to be a primary key column.";
|
||||
}
|
||||
}
|
||||
foreach ($assoc['joinTable']['inverseJoinColumns'] AS $inverseJoinColumn) {
|
||||
if (!isset($targetMetadata->fieldNames[$inverseJoinColumn['referencedColumnName']])) {
|
||||
$ce[] = "The inverse referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' does not " .
|
||||
"have a corresponding field with this column name on the class '" . $targetMetadata->name . "'.";
|
||||
break;
|
||||
}
|
||||
|
||||
$fieldName = $targetMetadata->fieldNames[$inverseJoinColumn['referencedColumnName']];
|
||||
if (!in_array($fieldName, $targetMetadata->identifier)) {
|
||||
$ce[] = "The referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' " .
|
||||
"has to be a primary key column.";
|
||||
}
|
||||
}
|
||||
|
||||
if (count($targetMetadata->getIdentifierColumnNames()) != count($assoc['joinTable']['inverseJoinColumns'])) {
|
||||
$ce[] = "The inverse join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " .
|
||||
"have to contain to ALL identifier columns of the target entity '". $targetMetadata->name . "', " .
|
||||
"however '" . implode(", ", array_diff($targetMetadata->getIdentifierColumnNames(), $assoc['relationToTargetKeyColumns'])) .
|
||||
"' are missing.";
|
||||
}
|
||||
|
||||
if (count($class->getIdentifierColumnNames()) != count($assoc['joinTable']['joinColumns'])) {
|
||||
$ce[] = "The join columns of the many-to-many table '" . $assoc['joinTable']['name'] . "' " .
|
||||
"have to contain to ALL identifier columns of the source entity '". $class->name . "', " .
|
||||
"however '" . implode(", ", array_diff($class->getIdentifierColumnNames(), $assoc['relationToSourceKeyColumns'])) .
|
||||
"' are missing.";
|
||||
}
|
||||
|
||||
} else if ($assoc['type'] & ClassMetadataInfo::TO_ONE) {
|
||||
foreach ($assoc['joinColumns'] AS $joinColumn) {
|
||||
if (!isset($targetMetadata->fieldNames[$joinColumn['referencedColumnName']])) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
|
||||
"have a corresponding field with this column name on the class '" . $targetMetadata->name . "'.";
|
||||
break;
|
||||
}
|
||||
|
||||
$fieldName = $targetMetadata->fieldNames[$joinColumn['referencedColumnName']];
|
||||
if (!in_array($fieldName, $targetMetadata->identifier)) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
|
||||
"has to be a primary key column.";
|
||||
}
|
||||
}
|
||||
|
||||
if (count($class->getIdentifierColumnNames()) != 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 . "', " .
|
||||
"however '" . implode(", ", array_diff($class->getIdentifierColumnNames(), $assoc['joinColumns'])) .
|
||||
"' are missing.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($assoc['orderBy']) && $assoc['orderBy'] !== null) {
|
||||
foreach ($assoc['orderBy'] AS $orderField => $orientation) {
|
||||
if (!$targetMetadata->hasField($orderField)) {
|
||||
$ce[] = "The association " . $class->name."#".$fieldName." is ordered by a foreign field " .
|
||||
$orderField . " that is not a field on the target entity " . $targetMetadata->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($class->reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $publicAttr) {
|
||||
if ($publicAttr->isStatic()) {
|
||||
continue;
|
||||
}
|
||||
$ce[] = "Field '".$publicAttr->getName()."' in class '".$class->name."' must be private ".
|
||||
"or protected. Public fields may break lazy-loading.";
|
||||
}
|
||||
|
||||
foreach ($class->subClasses AS $subClass) {
|
||||
if (!in_array($class->name, class_parents($subClass))) {
|
||||
$ce[] = "According to the discriminator map class '" . $subClass . "' has to be a child ".
|
||||
"of '" . $class->name . "' but these entities are not related through inheritance.";
|
||||
}
|
||||
}
|
||||
|
||||
return $ce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Database Schema is in sync with the current metadata state.
|
||||
*
|
||||
|
@ -1,11 +1,38 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools;
|
||||
|
||||
use Doctrine\ORM\ORMException;
|
||||
|
||||
/**
|
||||
* Tools related Exceptions
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class ToolsException extends ORMException
|
||||
{
|
||||
public static function schemaToolFailure($sql, \Exception $e)
|
||||
{
|
||||
return new self("Schema-Tool failed with Error '" . $e->getMessage() . "' while executing DDL: " . $sql, "0", $e);
|
||||
}
|
||||
|
||||
public static function couldNotMapDoctrine1Type($type)
|
||||
{
|
||||
return new self("Could not map doctrine 1 type '$type'!");
|
||||
|
@ -471,19 +471,21 @@ class UnitOfWork implements PropertyChangedListener
|
||||
*/
|
||||
public function computeChangeSet(ClassMetadata $class, $entity)
|
||||
{
|
||||
if ( ! $class->isInheritanceTypeNone()) {
|
||||
$class = $this->em->getClassMetadata(get_class($entity));
|
||||
}
|
||||
|
||||
$oid = spl_object_hash($entity);
|
||||
|
||||
if (isset($this->readOnlyObjects[$oid])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $class->isInheritanceTypeNone()) {
|
||||
$class = $this->em->getClassMetadata(get_class($entity));
|
||||
}
|
||||
|
||||
$actualData = array();
|
||||
|
||||
foreach ($class->reflFields as $name => $refProp) {
|
||||
$value = $refProp->getValue($entity);
|
||||
|
||||
if (isset($class->associationMappings[$name])
|
||||
&& ($class->associationMappings[$name]['type'] & ClassMetadata::TO_MANY)
|
||||
&& $value !== null
|
||||
@ -2054,6 +2056,11 @@ class UnitOfWork implements PropertyChangedListener
|
||||
// Loading the entity right here, if its in the eager loading map get rid of it there.
|
||||
unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
|
||||
|
||||
if (isset($this->eagerLoadingEntities[$class->rootEntityName]) &&
|
||||
! $this->eagerLoadingEntities[$class->rootEntityName]) {
|
||||
unset($this->eagerLoadingEntities[$class->rootEntityName]);
|
||||
}
|
||||
|
||||
// Properly initialize any unfetched associations, if partial objects are not allowed.
|
||||
if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
|
||||
foreach ($class->associationMappings as $field => $assoc) {
|
||||
|
@ -9,6 +9,7 @@ class DDC117Article
|
||||
{
|
||||
/** @Id @Column(type="integer", name="article_id") @GeneratedValue */
|
||||
private $id;
|
||||
|
||||
/** @Column */
|
||||
private $title;
|
||||
|
||||
|
@ -21,7 +21,7 @@ class LegacyUser
|
||||
*/
|
||||
public $_username;
|
||||
/**
|
||||
* @Column(type="string", length=255)
|
||||
* @Column(type="string", length=255, name="name")
|
||||
*/
|
||||
public $_name;
|
||||
/**
|
||||
|
@ -23,12 +23,12 @@ class LegacyUserReference
|
||||
private $_target;
|
||||
|
||||
/**
|
||||
* @column(type="string")
|
||||
* @column(type="string", name="description")
|
||||
*/
|
||||
private $_description;
|
||||
|
||||
/**
|
||||
* @column(type="datetime")
|
||||
* @column(type="datetime", name="created")
|
||||
*/
|
||||
private $_created;
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ -33,11 +31,13 @@ require_once __DIR__ . '/../../TestInit.php';
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
*/
|
||||
class CustomTreeWalkersTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
class CustomTreeWalkersTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
protected function setUp() {
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
private $_em;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->_em = $this->_getTestEntityManager();
|
||||
}
|
||||
|
||||
public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed)
|
||||
@ -70,7 +70,7 @@ class CustomTreeWalkersTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.email_id AS email_id4 FROM cms_users c0_ WHERE (c0_.name = ? OR c0_.name = ?) AND c0_.id = 1"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testSupportsQueriesWithSimpleConditionalExpression()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
@ -94,7 +94,7 @@ class CustomTreeWalker extends Query\TreeWalkerAdapter
|
||||
$dqlAliases[] = $dqlAlias;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create our conditions for all involved classes
|
||||
$factors = array();
|
||||
foreach ($dqlAliases as $alias) {
|
||||
@ -108,7 +108,7 @@ class CustomTreeWalker extends Query\TreeWalkerAdapter
|
||||
$factor = new Query\AST\ConditionalFactor($condPrimary);
|
||||
$factors[] = $factor;
|
||||
}
|
||||
|
||||
|
||||
if (($whereClause = $selectStatement->whereClause) !== null) {
|
||||
// There is already a WHERE clause, so append the conditions
|
||||
$condExpr = $whereClause->conditionalExpression;
|
||||
@ -119,18 +119,18 @@ class CustomTreeWalker extends Query\TreeWalkerAdapter
|
||||
|
||||
$whereClause->conditionalExpression = $condExpr;
|
||||
}
|
||||
|
||||
|
||||
$existingTerms = $whereClause->conditionalExpression->conditionalTerms;
|
||||
|
||||
|
||||
if (count($existingTerms) > 1) {
|
||||
// More than one term, so we need to wrap all these terms in a single root term
|
||||
// i.e: "WHERE u.name = :foo or u.other = :bar" => "WHERE (u.name = :foo or u.other = :bar) AND <our condition>"
|
||||
|
||||
|
||||
$primary = new Query\AST\ConditionalPrimary;
|
||||
$primary->conditionalExpression = new Query\AST\ConditionalExpression($existingTerms);
|
||||
$existingFactor = new Query\AST\ConditionalFactor($primary);
|
||||
$term = new Query\AST\ConditionalTerm(array_merge(array($existingFactor), $factors));
|
||||
|
||||
|
||||
$selectStatement->whereClause->conditionalExpression->conditionalTerms = array($term);
|
||||
} else {
|
||||
// Just one term so we can simply append our factors to that term
|
||||
|
@ -20,7 +20,9 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->_em->getConfiguration()->setEntityNamespaces(array());
|
||||
if ($this->_em) {
|
||||
$this->_em->getConfiguration()->setEntityNamespaces(array());
|
||||
}
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
@ -78,7 +80,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
return array($user->id, $address->id);
|
||||
}
|
||||
|
||||
|
||||
public function buildUser($name, $username, $status, $address)
|
||||
{
|
||||
$user = new CmsUser();
|
||||
@ -89,10 +91,10 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
||||
public function buildAddress($country, $city, $street, $zip)
|
||||
{
|
||||
$address = new CmsAddress();
|
||||
@ -103,7 +105,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->_em->persist($address);
|
||||
$this->_em->flush();
|
||||
|
||||
|
||||
return $address;
|
||||
}
|
||||
|
||||
@ -134,22 +136,22 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
$address1 = $this->buildAddress('Germany', 'Berlim', 'Foo st.', '123456');
|
||||
$user1 = $this->buildUser('Benjamin', 'beberlei', 'dev', $address1);
|
||||
|
||||
|
||||
$address2 = $this->buildAddress('Brazil', 'São Paulo', 'Bar st.', '654321');
|
||||
$user2 = $this->buildUser('Guilherme', 'guilhermeblanco', 'freak', $address2);
|
||||
|
||||
|
||||
$address3 = $this->buildAddress('USA', 'Nashville', 'Woo st.', '321654');
|
||||
$user3 = $this->buildUser('Jonathan', 'jwage', 'dev', $address3);
|
||||
|
||||
|
||||
unset($address1);
|
||||
unset($address2);
|
||||
unset($address3);
|
||||
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
$addresses = $repository->findBy(array('user' => array($user1->getId(), $user2->getId())));
|
||||
|
||||
|
||||
$this->assertEquals(2, count($addresses));
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress',$addresses[0]);
|
||||
}
|
||||
@ -158,22 +160,22 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
$address1 = $this->buildAddress('Germany', 'Berlim', 'Foo st.', '123456');
|
||||
$user1 = $this->buildUser('Benjamin', 'beberlei', 'dev', $address1);
|
||||
|
||||
|
||||
$address2 = $this->buildAddress('Brazil', 'São Paulo', 'Bar st.', '654321');
|
||||
$user2 = $this->buildUser('Guilherme', 'guilhermeblanco', 'freak', $address2);
|
||||
|
||||
|
||||
$address3 = $this->buildAddress('USA', 'Nashville', 'Woo st.', '321654');
|
||||
$user3 = $this->buildUser('Jonathan', 'jwage', 'dev', $address3);
|
||||
|
||||
|
||||
unset($address1);
|
||||
unset($address2);
|
||||
unset($address3);
|
||||
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsAddress');
|
||||
$addresses = $repository->findBy(array('user' => array($user1, $user2)));
|
||||
|
||||
|
||||
$this->assertEquals(2, count($addresses));
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsAddress',$addresses[0]);
|
||||
}
|
||||
@ -189,7 +191,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals('Guilherme', $users[0]->name);
|
||||
$this->assertEquals('dev', $users[0]->status);
|
||||
}
|
||||
|
||||
|
||||
public function testFindAll()
|
||||
{
|
||||
$user1Id = $this->loadFixture();
|
||||
@ -280,7 +282,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$userId = $user->id;
|
||||
|
||||
$this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId);
|
||||
|
||||
|
||||
$this->setExpectedException('Doctrine\ORM\OptimisticLockException');
|
||||
$this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $userId, \Doctrine\DBAL\LockMode::OPTIMISTIC);
|
||||
}
|
||||
@ -423,7 +425,7 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testFindByLimitOffset()
|
||||
{
|
||||
$this->loadFixture();
|
||||
|
||||
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser');
|
||||
|
||||
$users1 = $repos->findBy(array(), null, 1, 0);
|
||||
@ -451,8 +453,8 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertSame($usersAsc[0], $usersDesc[2]);
|
||||
$this->assertSame($usersAsc[2], $usersDesc[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-753
|
||||
*/
|
||||
@ -465,19 +467,19 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithDefaultCustomRepository');
|
||||
$this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753DefaultRepository", $repos);
|
||||
$this->assertTrue($repos->isDefaultRepository());
|
||||
|
||||
|
||||
|
||||
|
||||
$repos = $this->_em->getRepository('Doctrine\Tests\Models\DDC753\DDC753EntityWithCustomRepository');
|
||||
$this->assertInstanceOf("Doctrine\Tests\Models\DDC753\DDC753CustomRepository", $repos);
|
||||
$this->assertTrue($repos->isCustomRepository());
|
||||
|
||||
|
||||
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\Tests\Models\DDC753\DDC753DefaultRepository");
|
||||
$this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\ORM\EntityRepository");
|
||||
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-753
|
||||
* @expectedException Doctrine\ORM\ORMException
|
||||
@ -488,6 +490,6 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals($this->_em->getConfiguration()->getDefaultRepositoryClassName(), "Doctrine\ORM\EntityRepository");
|
||||
$this->_em->getConfiguration()->setDefaultRepositoryClassName("Doctrine\Tests\Models\DDC753\DDC753InvalidRepository");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
|
||||
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
|
||||
|
||||
|
||||
|
||||
$this->loadFixture();
|
||||
}
|
||||
|
||||
@ -137,9 +137,9 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
||||
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
|
||||
|
||||
$someGroups = $user->groups->slice(0, 2);
|
||||
|
||||
$this->assertContainsOnly('Doctrine\Tests\Models\CMS\CmsGroup', $someGroups);
|
||||
@ -225,7 +225,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
||||
|
||||
$article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId);
|
||||
|
||||
|
||||
$queryCount = $this->getCurrentQueryCount();
|
||||
$this->assertTrue($user->articles->contains($article));
|
||||
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
@ -304,6 +304,49 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1399
|
||||
*/
|
||||
public function testCountAfterAddThenFlush()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
|
||||
$newGroup = new \Doctrine\Tests\Models\CMS\CmsGroup();
|
||||
$newGroup->name = "Test4";
|
||||
|
||||
$user->addGroup($newGroup);
|
||||
$this->_em->persist($newGroup);
|
||||
|
||||
$this->assertFalse($user->groups->isInitialized());
|
||||
$this->assertEquals(4, count($user->groups));
|
||||
$this->assertFalse($user->groups->isInitialized());
|
||||
|
||||
$this->_em->flush();
|
||||
|
||||
$this->assertEquals(4, count($user->groups));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1462
|
||||
*/
|
||||
public function testSliceOnDirtyCollection()
|
||||
{
|
||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||
/* @var $user CmsUser */
|
||||
|
||||
$newGroup = new \Doctrine\Tests\Models\CMS\CmsGroup();
|
||||
$newGroup->name = "Test4";
|
||||
|
||||
$user->addGroup($newGroup);
|
||||
$this->_em->persist($newGroup);
|
||||
|
||||
$qc = $this->getCurrentQueryCount();
|
||||
$groups = $user->groups->slice(0, 10);
|
||||
|
||||
$this->assertEquals(4, count($groups));
|
||||
$this->assertEquals($qc + 1, $this->getCurrentQueryCount());
|
||||
}
|
||||
|
||||
private function loadFixture()
|
||||
{
|
||||
$user1 = new \Doctrine\Tests\Models\CMS\CmsUser();
|
||||
@ -364,7 +407,7 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->_em->persist($article1);
|
||||
$this->_em->persist($article2);
|
||||
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
@ -35,7 +35,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$user->status = 'dev';
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$rsm = new ResultSetMapping;
|
||||
@ -94,24 +94,24 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertEquals($addr->street, $addresses[0]->street);
|
||||
$this->assertTrue($addresses[0]->user instanceof CmsUser);
|
||||
}
|
||||
|
||||
|
||||
public function testJoinedOneToManyNativeQuery()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Roman';
|
||||
$user->username = 'romanb';
|
||||
$user->status = 'dev';
|
||||
|
||||
|
||||
$phone = new CmsPhonenumber;
|
||||
$phone->phonenumber = 424242;
|
||||
|
||||
|
||||
$user->addPhonenumber($phone);
|
||||
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$rsm = new ResultSetMapping;
|
||||
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
|
||||
$rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id');
|
||||
@ -119,7 +119,7 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$rsm->addFieldResult('u', $this->platform->getSQLResultCasing('status'), 'status');
|
||||
$rsm->addJoinedEntityResult('Doctrine\Tests\Models\CMS\CmsPhonenumber', 'p', 'u', 'phonenumbers');
|
||||
$rsm->addFieldResult('p', $this->platform->getSQLResultCasing('phonenumber'), 'phonenumber');
|
||||
|
||||
|
||||
$query = $this->_em->createNativeQuery('SELECT id, name, status, phonenumber FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username = ?', $rsm);
|
||||
$query->setParameter(1, 'romanb');
|
||||
|
||||
@ -133,30 +133,30 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$phones = $users[0]->getPhonenumbers();
|
||||
$this->assertEquals(424242, $phones[0]->phonenumber);
|
||||
$this->assertTrue($phones[0]->getUser() === $users[0]);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testJoinedOneToOneNativeQuery()
|
||||
{
|
||||
$user = new CmsUser;
|
||||
$user->name = 'Roman';
|
||||
$user->username = 'romanb';
|
||||
$user->status = 'dev';
|
||||
|
||||
|
||||
$addr = new CmsAddress;
|
||||
$addr->country = 'germany';
|
||||
$addr->zip = 10827;
|
||||
$addr->city = 'Berlin';
|
||||
|
||||
|
||||
|
||||
|
||||
$user->setAddress($addr);
|
||||
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
|
||||
|
||||
$rsm = new ResultSetMapping;
|
||||
$rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
|
||||
$rsm->addFieldResult('u', $this->platform->getSQLResultCasing('id'), 'id');
|
||||
@ -167,12 +167,12 @@ class NativeQueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$rsm->addFieldResult('a', $this->platform->getSQLResultCasing('country'), 'country');
|
||||
$rsm->addFieldResult('a', $this->platform->getSQLResultCasing('zip'), 'zip');
|
||||
$rsm->addFieldResult('a', $this->platform->getSQLResultCasing('city'), 'city');
|
||||
|
||||
|
||||
$query = $this->_em->createNativeQuery('SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?', $rsm);
|
||||
$query->setParameter(1, 'romanb');
|
||||
|
||||
|
||||
$users = $query->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(1, count($users));
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\CMS\CmsUser', $users[0]);
|
||||
$this->assertEquals('Roman', $users[0]->name);
|
||||
|
@ -27,14 +27,14 @@ class ReadOnlyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->flush();
|
||||
|
||||
$readOnly->name = "Test2";
|
||||
$readOnly->number = 4321;
|
||||
$readOnly->numericValue = 4321;
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$dbReadOnly = $this->_em->find('Doctrine\Tests\ORM\Functional\ReadOnlyEntity', $readOnly->id);
|
||||
$this->assertEquals("Test1", $dbReadOnly->name);
|
||||
$this->assertEquals(1234, $dbReadOnly->number);
|
||||
$this->assertEquals(1234, $dbReadOnly->numericValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,11 +51,11 @@ class ReadOnlyEntity
|
||||
/** @column(type="string") */
|
||||
public $name;
|
||||
/** @Column(type="integer") */
|
||||
public $number;
|
||||
public $numericValue;
|
||||
|
||||
public function __construct($name, $number)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->number = $number;
|
||||
$this->numericValue = $number;
|
||||
}
|
||||
}
|
@ -90,10 +90,10 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testUseResultCache()
|
||||
{
|
||||
$cache = new \Doctrine\Common\Cache\ArrayCache();
|
||||
$this->_em->getConfiguration()->setResultCacheImpl($cache);
|
||||
|
||||
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
|
||||
$query->useResultCache(true);
|
||||
$query->setResultCacheDriver($cache);
|
||||
$query->setResultCacheId('testing_result_cache_id');
|
||||
$users = $query->getResult();
|
||||
|
||||
@ -108,11 +108,11 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testUseResultCacheParams()
|
||||
{
|
||||
$cache = new \Doctrine\Common\Cache\ArrayCache();
|
||||
$this->_em->getConfiguration()->setResultCacheImpl($cache);
|
||||
|
||||
$sqlCount = count($this->_sqlLoggerStack->queries);
|
||||
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux WHERE ux.id = ?1');
|
||||
$query->setParameter(1, 1);
|
||||
$query->setResultCacheDriver($cache);
|
||||
$query->useResultCache(true);
|
||||
$query->getResult();
|
||||
|
||||
@ -149,10 +149,10 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <type> $query
|
||||
* @param string $query
|
||||
* @depends testNativeQueryResultCaching
|
||||
*/
|
||||
public function testResultCacheDependsOnQueryHints($query)
|
||||
public function testResultCacheNotDependsOnQueryHints($query)
|
||||
{
|
||||
$cache = $query->getResultCacheDriver();
|
||||
$cacheCount = $this->getCacheSize($cache);
|
||||
@ -160,7 +160,7 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$query->setHint('foo', 'bar');
|
||||
$query->getResult();
|
||||
|
||||
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
|
||||
$this->assertEquals($cacheCount, $this->getCacheSize($cache));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,7 +182,7 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
* @param <type> $query
|
||||
* @depends testNativeQueryResultCaching
|
||||
*/
|
||||
public function testResultCacheDependsOnHydrationMode($query)
|
||||
public function testResultCacheNotDependsOnHydrationMode($query)
|
||||
{
|
||||
$cache = $query->getResultCacheDriver();
|
||||
$cacheCount = $this->getCacheSize($cache);
|
||||
@ -190,7 +190,7 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->assertNotEquals(\Doctrine\ORM\Query::HYDRATE_ARRAY, $query->getHydrationMode());
|
||||
$query->getArrayResult();
|
||||
|
||||
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
|
||||
$this->assertEquals($cacheCount, $this->getCacheSize($cache));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$user->name = "John Galt";
|
||||
$user->username = "jgalt";
|
||||
$user->status = "inactive";
|
||||
|
||||
|
||||
$article = new CmsArticle();
|
||||
$article->topic = "This is John Galt speaking!";
|
||||
$article->text = "Yadda Yadda!";
|
||||
@ -44,11 +44,10 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
->setParameter('author', $user)
|
||||
->getResult();
|
||||
|
||||
$dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = :topic AND a.user = :author AND a.user = :author AND a.text = :text";
|
||||
$dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = :topic AND a.user = :author AND a.user = :author";
|
||||
$farticle = $this->_em->createQuery($dql)
|
||||
->setParameter('author', $user)
|
||||
->setParameter('topic', 'This is John Galt speaking!')
|
||||
->setParameter('text', 'Yadda Yadda!')
|
||||
->getSingleResult();
|
||||
|
||||
$this->assertSame($article, $farticle);
|
||||
@ -70,12 +69,11 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->persist($article);
|
||||
$this->_em->flush();
|
||||
|
||||
$dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = ?1 AND a.user = ?2 AND a.user = ?3 AND a.text = ?4";
|
||||
$dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.topic = ?1 AND a.user = ?2 AND a.user = ?3";
|
||||
$farticle = $this->_em->createQuery($dql)
|
||||
->setParameter(1, 'This is John Galt speaking!')
|
||||
->setParameter(2, $user)
|
||||
->setParameter(3, $user)
|
||||
->setParameter(4, 'Yadda Yadda!')
|
||||
->getSingleResult();
|
||||
|
||||
$this->assertSame($article, $farticle);
|
||||
|
@ -106,7 +106,7 @@ class DDC1209_3
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="datetime")
|
||||
* @Column(type="datetime", name="somedate")
|
||||
*/
|
||||
private $date;
|
||||
|
||||
|
@ -21,10 +21,10 @@ class DDC1225Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1225_TestEntity2'),
|
||||
));
|
||||
} catch(\PDOException $e) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$qb = $this->_em->createQueryBuilder();
|
||||
@ -32,10 +32,10 @@ class DDC1225Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
->select('te1')
|
||||
->where('te1.testEntity2 = ?1')
|
||||
->setParameter(1, 0);
|
||||
|
||||
|
||||
$this->assertEquals(
|
||||
'SELECT t0_.test_entity2_id AS test_entity2_id0 FROM te1 t0_ WHERE t0_.test_entity2_id = ?',
|
||||
$qb->getQuery()->getSQL()
|
||||
strtolower('SELECT t0_.test_entity2_id AS test_entity2_id0 FROM te1 t0_ WHERE t0_.test_entity2_id = ?'),
|
||||
strtolower($qb->getQuery()->getSQL())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -21,58 +21,58 @@ class DDC1228Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228User'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228Profile'),
|
||||
));
|
||||
} catch(\PDOException $e) {
|
||||
|
||||
} catch(\Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testOneToOnePersist()
|
||||
{
|
||||
$user = new DDC1228User;
|
||||
$profile = new DDC1228Profile();
|
||||
$profile->name = "Foo";
|
||||
$user->profile = $profile;
|
||||
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->persist($profile);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id);
|
||||
|
||||
|
||||
$this->assertFalse($user->getProfile()->__isInitialized__, "Proxy is not initialized");
|
||||
$user->getProfile()->setName("Bar");
|
||||
$this->assertTrue($user->getProfile()->__isInitialized__, "Proxy is not initialized");
|
||||
|
||||
|
||||
$this->assertEquals("Bar", $user->getProfile()->getName());
|
||||
$this->assertEquals(array("id" => 1, "name" => "Foo"), $this->_em->getUnitOfWork()->getOriginalEntityData($user->getProfile()));
|
||||
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id);
|
||||
$this->assertEquals("Bar", $user->getProfile()->getName());
|
||||
}
|
||||
|
||||
|
||||
public function testRefresh()
|
||||
{
|
||||
$user = new DDC1228User;
|
||||
$profile = new DDC1228Profile();
|
||||
$profile->name = "Foo";
|
||||
$user->profile = $profile;
|
||||
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->persist($profile);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1228User', $user->id);
|
||||
|
||||
|
||||
$this->_em->refresh($user);
|
||||
$user->name = "Baz";
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$user = $this->_em->find(__NAMESPACE__ . '\\DDC1228User', $user->id);
|
||||
$this->assertEquals("Baz", $user->name);
|
||||
}
|
||||
@ -88,20 +88,20 @@ class DDC1228User
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
|
||||
/**
|
||||
* @column(type="string")
|
||||
* @Column(type="string")
|
||||
* @var string
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
public $name = 'Bar';
|
||||
|
||||
/**
|
||||
* @OneToOne(targetEntity="DDC1228Profile")
|
||||
* @var Profile
|
||||
*/
|
||||
public $profile;
|
||||
|
||||
public function getProfile()
|
||||
|
||||
public function getProfile()
|
||||
{
|
||||
return $this->profile;
|
||||
}
|
||||
@ -117,13 +117,13 @@ class DDC1228Profile
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
|
||||
/**
|
||||
* @column(type="string")
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
|
@ -19,49 +19,49 @@ class DDC1238Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1238User'),
|
||||
));
|
||||
} catch(\PDOException $e) {
|
||||
|
||||
} catch(\Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testIssue()
|
||||
{
|
||||
$user = new DDC1238User;
|
||||
$user->setName("test");
|
||||
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$userId = $user->getId();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$userId2 = $user->getId();
|
||||
$this->assertEquals($userId, $userId2, "This proxy can still be initialized.");
|
||||
}
|
||||
|
||||
|
||||
public function testIssueProxyClear()
|
||||
{
|
||||
$user = new DDC1238User;
|
||||
$user->setName("test");
|
||||
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
// force proxy load, getId() doesn't work anymore
|
||||
$user->getName();
|
||||
$userId = $user->getId();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$user = $this->_em->getReference(__NAMESPACE__ . '\\DDC1238User', $userId);
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$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");
|
||||
@ -75,18 +75,18 @@ class DDC1238User
|
||||
{
|
||||
/** @Id @GeneratedValue @Column(type="integer") */
|
||||
private $id;
|
||||
|
||||
|
||||
/**
|
||||
* @Column
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
|
@ -7,56 +7,56 @@ use DateTime;
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-1135
|
||||
* @group DDC-1335
|
||||
*/
|
||||
class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
class DDC1335Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1135User'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1135Phone'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1335User'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1335Phone'),
|
||||
));
|
||||
$this->loadFixture();
|
||||
} catch(\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public function testDql()
|
||||
{
|
||||
$dql = 'SELECT u FROM ' . __NAMESPACE__ . '\DDC1135User u INDEX BY u.id';
|
||||
$dql = 'SELECT u FROM ' . __NAMESPACE__ . '\DDC1335User u INDEX BY u.id';
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$result = $query->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(sizeof($result), 3);
|
||||
$this->assertArrayHasKey(1, $result);
|
||||
$this->assertArrayHasKey(2, $result);
|
||||
$this->assertArrayHasKey(3, $result);
|
||||
|
||||
$dql = 'SELECT u, p FROM '.__NAMESPACE__ . '\DDC1135User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id';
|
||||
|
||||
$dql = 'SELECT u, p FROM '.__NAMESPACE__ . '\DDC1335User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id';
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$result = $query->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(sizeof($result), 3);
|
||||
$this->assertArrayHasKey('foo@foo.com', $result);
|
||||
$this->assertArrayHasKey('bar@bar.com', $result);
|
||||
$this->assertArrayHasKey('foobar@foobar.com', $result);
|
||||
|
||||
|
||||
$this->assertEquals(sizeof($result['foo@foo.com']->phones), 3);
|
||||
$this->assertEquals(sizeof($result['bar@bar.com']->phones), 3);
|
||||
$this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3);
|
||||
|
||||
|
||||
$this->assertArrayHasKey(1, $result['foo@foo.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(2, $result['foo@foo.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(3, $result['foo@foo.com']->phones->toArray());
|
||||
|
||||
|
||||
$this->assertArrayHasKey(4, $result['bar@bar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(5, $result['bar@bar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(6, $result['bar@bar.com']->phones->toArray());
|
||||
|
||||
|
||||
$this->assertArrayHasKey(7, $result['foobar@foobar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(8, $result['foobar@foobar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(9, $result['foobar@foobar.com']->phones->toArray());
|
||||
@ -65,77 +65,77 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testTicket()
|
||||
{
|
||||
$builder = $this->_em->createQueryBuilder();
|
||||
$builder->select('u')->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.id');
|
||||
$builder->select('u')->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.id');
|
||||
|
||||
$dql = $builder->getQuery()->getDQL();
|
||||
$result = $builder->getQuery()->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(sizeof($result), 3);
|
||||
$this->assertArrayHasKey(1, $result);
|
||||
$this->assertArrayHasKey(2, $result);
|
||||
$this->assertArrayHasKey(3, $result);
|
||||
$this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1135User u INDEX BY u.id', $dql);
|
||||
$this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1335User u INDEX BY u.id', $dql);
|
||||
}
|
||||
|
||||
|
||||
public function testIndexByUnique()
|
||||
{
|
||||
$builder = $this->_em->createQueryBuilder();
|
||||
$builder->select('u')->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.email');
|
||||
$builder->select('u')->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.email');
|
||||
|
||||
$dql = $builder->getQuery()->getDQL();
|
||||
$result = $builder->getQuery()->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(sizeof($result), 3);
|
||||
$this->assertArrayHasKey('foo@foo.com', $result);
|
||||
$this->assertArrayHasKey('bar@bar.com', $result);
|
||||
$this->assertArrayHasKey('foobar@foobar.com', $result);
|
||||
$this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1135User u INDEX BY u.email', $dql);
|
||||
$this->assertEquals('SELECT u FROM ' . __NAMESPACE__ . '\DDC1335User u INDEX BY u.email', $dql);
|
||||
}
|
||||
|
||||
|
||||
public function testIndexWithJoin()
|
||||
{
|
||||
$builder = $this->_em->createQueryBuilder();
|
||||
$builder->select('u','p')
|
||||
->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.email')
|
||||
->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.email')
|
||||
->join('u.phones', 'p', null, null, 'p.id');
|
||||
|
||||
|
||||
$dql = $builder->getQuery()->getDQL();
|
||||
$result = $builder->getQuery()->getResult();
|
||||
|
||||
|
||||
$this->assertEquals(sizeof($result), 3);
|
||||
$this->assertArrayHasKey('foo@foo.com', $result);
|
||||
$this->assertArrayHasKey('bar@bar.com', $result);
|
||||
$this->assertArrayHasKey('foobar@foobar.com', $result);
|
||||
|
||||
|
||||
$this->assertEquals(sizeof($result['foo@foo.com']->phones), 3);
|
||||
$this->assertEquals(sizeof($result['bar@bar.com']->phones), 3);
|
||||
$this->assertEquals(sizeof($result['foobar@foobar.com']->phones), 3);
|
||||
|
||||
|
||||
$this->assertArrayHasKey(1, $result['foo@foo.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(2, $result['foo@foo.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(3, $result['foo@foo.com']->phones->toArray());
|
||||
|
||||
|
||||
$this->assertArrayHasKey(4, $result['bar@bar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(5, $result['bar@bar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(6, $result['bar@bar.com']->phones->toArray());
|
||||
|
||||
|
||||
$this->assertArrayHasKey(7, $result['foobar@foobar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(8, $result['foobar@foobar.com']->phones->toArray());
|
||||
$this->assertArrayHasKey(9, $result['foobar@foobar.com']->phones->toArray());
|
||||
|
||||
$this->assertEquals('SELECT u, p FROM '.__NAMESPACE__ . '\DDC1135User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id', $dql);
|
||||
|
||||
$this->assertEquals('SELECT u, p FROM '.__NAMESPACE__ . '\DDC1335User u INDEX BY u.email INNER JOIN u.phones p INDEX BY p.id', $dql);
|
||||
}
|
||||
|
||||
|
||||
private function loadFixture()
|
||||
{
|
||||
$p1 = array('11 xxxx-xxxx','11 yyyy-yyyy','11 zzzz-zzzz');
|
||||
$p2 = array('22 xxxx-xxxx','22 yyyy-yyyy','22 zzzz-zzzz');
|
||||
$p3 = array('33 xxxx-xxxx','33 yyyy-yyyy','33 zzzz-zzzz');
|
||||
|
||||
$u1 = new DDC1135User("foo@foo.com", "Foo",$p1);
|
||||
$u2 = new DDC1135User("bar@bar.com", "Bar",$p2);
|
||||
$u3 = new DDC1135User("foobar@foobar.com", "Foo Bar",$p3);
|
||||
|
||||
|
||||
$u1 = new DDC1335User("foo@foo.com", "Foo",$p1);
|
||||
$u2 = new DDC1335User("bar@bar.com", "Bar",$p2);
|
||||
$u3 = new DDC1335User("foobar@foobar.com", "Foo Bar",$p3);
|
||||
|
||||
$this->_em->persist($u1);
|
||||
$this->_em->persist($u2);
|
||||
$this->_em->persist($u3);
|
||||
@ -148,7 +148,7 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1135User
|
||||
class DDC1335User
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer")
|
||||
@ -160,25 +160,25 @@ class DDC1135User
|
||||
* @Column(type="string", unique=true)
|
||||
*/
|
||||
public $email;
|
||||
|
||||
|
||||
/**
|
||||
* @Column(type="string")
|
||||
*/
|
||||
public $name;
|
||||
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity="DDC1135Phone", mappedBy="user", cascade={"persist", "remove"})
|
||||
* @OneToMany(targetEntity="DDC1335Phone", mappedBy="user", cascade={"persist", "remove"})
|
||||
*/
|
||||
public $phones;
|
||||
|
||||
|
||||
public function __construct($email, $name, array $numbers = array())
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->email = $email;
|
||||
$this->phones = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
|
||||
|
||||
foreach ($numbers as $number) {
|
||||
$this->phones->add(new DDC1135Phone($this,$number));
|
||||
$this->phones->add(new DDC1335Phone($this,$number));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -186,22 +186,22 @@ class DDC1135User
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1135Phone
|
||||
class DDC1335Phone
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(name="id", type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @Column(name="number", type="string", nullable = false)
|
||||
* @Column(name="numericalValue", type="string", nullable = false)
|
||||
*/
|
||||
public $number;
|
||||
public $numericalValue;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="DDC1135User", inversedBy="phones")
|
||||
* @ManyToOne(targetEntity="DDC1335User", inversedBy="phones")
|
||||
* @JoinColumn(name="user_id", referencedColumnName="id", nullable = false)
|
||||
*/
|
||||
public $user;
|
||||
@ -209,6 +209,6 @@ class DDC1135Phone
|
||||
public function __construct($user, $number)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->number = $number;
|
||||
$this->numericalValue = $number;
|
||||
}
|
||||
}
|
69
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1454Test.php
Normal file
69
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1454Test.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
require_once __DIR__ . '/../../../TestInit.php';
|
||||
|
||||
/**
|
||||
* @group DDC-1454
|
||||
*/
|
||||
class DDC1454Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1454File'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1454Picture'),
|
||||
));
|
||||
} catch (\Exception $ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function testFailingCase()
|
||||
{
|
||||
$pic = new DDC1454Picture();
|
||||
$this->_em->getUnitOfWork()->getEntityState($pic);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1454Picture extends DDC1454File
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("JOINED")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"picture" = "DDC1454Picture"})
|
||||
*/
|
||||
class DDC1454File
|
||||
{
|
||||
/**
|
||||
* @Column(name="file_id", type="integer")
|
||||
* @Id
|
||||
*/
|
||||
public $fileId;
|
||||
|
||||
public function __construct() {
|
||||
$this->fileId = rand();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fileId
|
||||
*/
|
||||
public function getFileId() {
|
||||
return $this->fileId;
|
||||
}
|
||||
|
||||
}
|
@ -25,18 +25,15 @@ class DDC331Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-331
|
||||
*/
|
||||
public function testSelectFieldOnRootEntity()
|
||||
{
|
||||
$employee = new CompanyEmployee;
|
||||
$employee->setName('Roman S. Borschel');
|
||||
$employee->setSalary(100000);
|
||||
$employee->setDepartment('IT');
|
||||
|
||||
$this->_em->persist($employee);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$q = $this->_em->createQuery('SELECT e.name FROM Doctrine\Tests\Models\Company\CompanyEmployee e');
|
||||
$this->assertEquals('SELECT c0_.name AS name0 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id', $q->getSql());
|
||||
$this->assertEquals(
|
||||
strtolower('SELECT c0_.name AS name0 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id'),
|
||||
strtolower($q->getSql())
|
||||
);
|
||||
}
|
||||
}
|
@ -18,7 +18,10 @@ class DDC448Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testIssue()
|
||||
{
|
||||
$q = $this->_em->createQuery("select b from ".__NAMESPACE__."\\DDC448SubTable b where b.connectedClassId = ?1");
|
||||
$this->assertEquals('SELECT d0_.id AS id0, d0_.discr AS discr1, d0_.connectedClassId AS connectedClassId2 FROM SubTable s1_ INNER JOIN DDC448MainTable d0_ ON s1_.id = d0_.id WHERE d0_.connectedClassId = ?', $q->getSQL());
|
||||
$this->assertEquals(
|
||||
strtolower('SELECT d0_.id AS id0, d0_.discr AS discr1, d0_.connectedClassId AS connectedClassId2 FROM SubTable s1_ INNER JOIN DDC448MainTable d0_ ON s1_.id = d0_.id WHERE d0_.connectedClassId = ?'),
|
||||
strtolower($q->getSQL())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,10 @@ class DDC493Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testIssue()
|
||||
{
|
||||
$q = $this->_em->createQuery("select u, c.data from ".__NAMESPACE__."\\DDC493Distributor u JOIN u.contact c");
|
||||
$this->assertEquals('SELECT d0_.id AS id0, d1_.data AS data1, d0_.discr AS discr2, d0_.contact AS contact3 FROM DDC493Distributor d2_ INNER JOIN DDC493Customer d0_ ON d2_.id = d0_.id INNER JOIN DDC493Contact d1_ ON d0_.contact = d1_.id', $q->getSQL());
|
||||
$this->assertEquals(
|
||||
strtolower('SELECT d0_.id AS id0, d1_.data AS data1, d0_.discr AS discr2, d0_.contact AS contact3 FROM DDC493Distributor d2_ INNER JOIN DDC493Customer d0_ ON d2_.id = d0_.id INNER JOIN DDC493Contact d1_ ON d0_.contact = d1_.id'),
|
||||
strtolower($q->getSQL())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,10 @@ class DDC513Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
public function testIssue()
|
||||
{
|
||||
$q = $this->_em->createQuery("select u from ".__NAMESPACE__."\\DDC513OfferItem u left join u.price p");
|
||||
$this->assertEquals('SELECT d0_.id AS id0, d0_.discr AS discr1, d0_.price AS price2 FROM DDC513OfferItem d1_ INNER JOIN DDC513Item d0_ ON d1_.id = d0_.id LEFT JOIN DDC513Price d2_ ON d0_.price = d2_.id', $q->getSQL());
|
||||
$this->assertEquals(
|
||||
strtolower('SELECT d0_.id AS id0, d0_.discr AS discr1, d0_.price AS price2 FROM DDC513OfferItem d1_ INNER JOIN DDC513Item d0_ ON d1_.id = d0_.id LEFT JOIN DDC513Price d2_ ON d0_.price = d2_.id'),
|
||||
strtolower($q->getSQL())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,10 @@ class DDC698Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$sql = $qb->getQuery()->getSQL();
|
||||
|
||||
$this->assertEquals('SELECT p0_.privilegeID AS privilegeID0, p0_.name AS name1, r1_.roleID AS roleID2, r1_.name AS name3, r1_.shortName AS shortName4 FROM Privileges p0_ LEFT JOIN RolePrivileges r2_ ON p0_.privilegeID = r2_.privilegeID LEFT JOIN Roles r1_ ON r1_.roleID = r2_.roleID', $sql);
|
||||
$this->assertEquals(
|
||||
strtolower('SELECT p0_.privilegeID AS privilegeID0, p0_.name AS name1, r1_.roleID AS roleID2, r1_.name AS name3, r1_.shortName AS shortName4 FROM Privileges p0_ LEFT JOIN RolePrivileges r2_ ON p0_.privilegeID = r2_.privilegeID LEFT JOIN Roles r1_ ON r1_.roleID = r2_.roleID'),
|
||||
strtolower($sql)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,10 @@ class DDC719Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
$q = $this->_em->createQuery('SELECT g, c FROM Doctrine\Tests\ORM\Functional\Ticket\DDC719Group g LEFT JOIN g.children c WHERE g.parents IS EMPTY');
|
||||
|
||||
$this->assertEquals('SELECT g0_.name AS name0, g0_.description AS description1, g0_.id AS id2, g1_.name AS name3, g1_.description AS description4, g1_.id AS id5 FROM groups g0_ LEFT JOIN groups_groups g2_ ON g0_.id = g2_.parent_id LEFT JOIN groups g1_ ON g1_.id = g2_.child_id WHERE (SELECT COUNT(*) FROM groups_groups g3_ WHERE g3_.child_id = g0_.id) = 0', $q->getSQL());
|
||||
$this->assertEquals(
|
||||
strtolower('SELECT g0_.name AS name0, g0_.description AS description1, g0_.id AS id2, g1_.name AS name3, g1_.description AS description4, g1_.id AS id5 FROM groups g0_ LEFT JOIN groups_groups g2_ ON g0_.id = g2_.parent_id LEFT JOIN groups g1_ ON g1_.id = g2_.child_id WHERE (SELECT COUNT(*) FROM groups_groups g3_ WHERE g3_.child_id = g0_.id) = 0'),
|
||||
strtolower($q->getSQL())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,12 +31,12 @@ class DDC719Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
*/
|
||||
class Entity
|
||||
{
|
||||
/**
|
||||
/**
|
||||
* @Id @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
* @Column(type="integer")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
|
||||
public function getId() { return $this->id; }
|
||||
}
|
||||
|
||||
|
@ -34,10 +34,10 @@ class DDC949Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$true = $this->_em->getRepository('Doctrine\Tests\Models\Generic\BooleanModel')->findOneBy(array('booleanField' => true));
|
||||
$false = $this->_em->getRepository('Doctrine\Tests\Models\Generic\BooleanModel')->findOneBy(array('booleanField' => false));
|
||||
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Generic\BooleanModel', $true);
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Generic\BooleanModel', $true, "True model not found");
|
||||
$this->assertTrue($true->booleanField, "True Boolean Model should be true.");
|
||||
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Generic\BooleanModel', $false);
|
||||
$this->assertInstanceOf('Doctrine\Tests\Models\Generic\BooleanModel', $false, "False model not found");
|
||||
$this->assertFalse($false->booleanField, "False Boolean Model should be false.");
|
||||
}
|
||||
}
|
@ -17,11 +17,11 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
|
||||
/**
|
||||
* Assert a valid SQL generation.
|
||||
*
|
||||
*
|
||||
* @param string $dqlToBeTested
|
||||
* @param string $sqlToBeConfirmed
|
||||
* @param array $queryHints
|
||||
* @param array $queryParams
|
||||
* @param array $queryParams
|
||||
*/
|
||||
public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed, array $queryHints = array(), array $queryParams = array())
|
||||
{
|
||||
@ -34,11 +34,11 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
|
||||
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)
|
||||
->useQueryCache(false);
|
||||
|
||||
|
||||
foreach ($queryHints AS $name => $value) {
|
||||
$query->setHint($name, $value);
|
||||
}
|
||||
|
||||
|
||||
parent::assertEquals($sqlToBeConfirmed, $query->getSQL());
|
||||
$query->free();
|
||||
} catch (\Exception $e) {
|
||||
@ -383,7 +383,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testSupportsInstanceOfExpressionInWherePartWithMultipleValues()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
@ -391,7 +391,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee', 'manager')"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-1194
|
||||
*/
|
||||
@ -402,7 +402,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-1194
|
||||
*/
|
||||
@ -604,7 +604,24 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
. ' WHERE EXISTS ('
|
||||
. 'SELECT c1_.id FROM cms_employees c1_ WHERE c1_.id = c0_.spouse_id'
|
||||
. ')'
|
||||
);
|
||||
}
|
||||
|
||||
public function testExistsExpressionWithSimpleSelectReturningScalar()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
// DQL
|
||||
// The result of this query consists of all employees whose spouses are also employees.
|
||||
'SELECT DISTINCT emp FROM Doctrine\Tests\Models\CMS\CmsEmployee emp
|
||||
WHERE EXISTS (
|
||||
SELECT 1
|
||||
FROM Doctrine\Tests\Models\CMS\CmsEmployee spouseEmp
|
||||
WHERE spouseEmp = emp.spouse)',
|
||||
// SQL
|
||||
'SELECT DISTINCT c0_.id AS id0, c0_.name AS name1 FROM cms_employees c0_'
|
||||
. ' WHERE EXISTS ('
|
||||
. 'SELECT 1 AS sclr2 FROM cms_employees c1_ WHERE c1_.id = c0_.spouse_id'
|
||||
. ')'
|
||||
);
|
||||
}
|
||||
|
||||
@ -686,7 +703,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, (SELECT COUNT(*) FROM cms_articles c1_ WHERE c1_.user_id = c0_.id) AS sclr4 FROM cms_users c0_ ORDER BY sclr4 ASC"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testOrderBySupportsSingleValuedPathExpressionOwningSide()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
@ -694,7 +711,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"SELECT c0_.id AS id0, c0_.topic AS topic1, c0_.text AS text2, c0_.version AS version3 FROM cms_articles c0_ ORDER BY c0_.user_id ASC"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @expectedException Doctrine\ORM\Query\QueryException
|
||||
*/
|
||||
@ -729,12 +746,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);
|
||||
@ -877,7 +894,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'",
|
||||
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 ".
|
||||
"SELECT c0_.id AS ID0, c0_.status AS STATUS1, c0_.username AS USERNAME2, c0_.name AS NAME3 ".
|
||||
"FROM cms_users c0_ WHERE c0_.username = 'gblanco' FOR UPDATE",
|
||||
array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::PESSIMISTIC_READ)
|
||||
);
|
||||
@ -931,7 +948,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
'SELECT c0_.id AS id0, c0_.name AS name1, count(c1_.id) AS sclr2 FROM cms_groups c0_ INNER JOIN cms_users_groups c2_ ON c0_.id = c2_.group_id INNER JOIN cms_users c1_ ON c1_.id = c2_.user_id GROUP BY c0_.id'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testCaseContainingNullIf()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
@ -939,7 +956,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
'SELECT NULLIF(c0_.id, c0_.name) AS sclr0 FROM cms_groups c0_'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testCaseContainingCoalesce()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
@ -1009,248 +1026,281 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
"SELECT d0_.article_id AS article_id0, d0_.title AS title1, d1_.article_id AS article_id2, d1_.title AS title3 FROM DDC117Link d2_ INNER JOIN DDC117Article d0_ ON d2_.target_id = d0_.article_id INNER JOIN DDC117Article d1_ ON d2_.source_id = d1_.article_id"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testGeneralCaseWithSingleWhenClause()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT g.id, CASE WHEN ((g.id / 2) > 18) THEN 1 ELSE 0 END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g",
|
||||
"SELECT g.id, CASE WHEN ((g.id / 2) > 18) THEN 1 ELSE 0 END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g",
|
||||
"SELECT c0_.id AS id0, CASE WHEN (c0_.id / 2 > 18) THEN 1 ELSE 0 END AS sclr1 FROM cms_groups c0_"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testGeneralCaseWithMultipleWhenClause()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT g.id, CASE WHEN (g.id / 2 < 10) THEN 2 WHEN ((g.id / 2) > 20) THEN 1 ELSE 0 END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g",
|
||||
"SELECT g.id, CASE WHEN (g.id / 2 < 10) THEN 2 WHEN ((g.id / 2) > 20) THEN 1 ELSE 0 END AS test FROM Doctrine\Tests\Models\CMS\CmsGroup g",
|
||||
"SELECT c0_.id AS id0, CASE WHEN (c0_.id / 2 < 10) THEN 2 WHEN (c0_.id / 2 > 20) THEN 1 ELSE 0 END AS sclr1 FROM cms_groups c0_"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testSimpleCaseWithSingleWhenClause()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id = CASE g.name WHEN 'admin' THEN 1 ELSE 2 END",
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id = CASE g.name WHEN 'admin' THEN 1 ELSE 2 END",
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id = CASE c0_.name WHEN admin THEN 1 ELSE 2 END"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testSimpleCaseWithMultipleWhenClause()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id = (CASE g.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END)",
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id = (CASE g.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END)",
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id = CASE c0_.name WHEN admin THEN 1 WHEN moderator THEN 2 ELSE 3 END"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testGeneralCaseWithSingleWhenClauseInSubselect()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE WHEN ((g2.id / 2) > 18) THEN 2 ELSE 1 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE WHEN ((g2.id / 2) > 18) THEN 2 ELSE 1 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE WHEN (c1_.id / 2 > 18) THEN 2 ELSE 1 END AS sclr2 FROM cms_groups c1_)"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testGeneralCaseWithMultipleWhenClauseInSubselect()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE WHEN (g.id / 2 < 10) THEN 3 WHEN ((g.id / 2) > 20) THEN 2 ELSE 1 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE WHEN (g.id / 2 < 10) THEN 3 WHEN ((g.id / 2) > 20) THEN 2 ELSE 1 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE WHEN (c0_.id / 2 < 10) THEN 3 WHEN (c0_.id / 2 > 20) THEN 2 ELSE 1 END AS sclr2 FROM cms_groups c1_)"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testSimpleCaseWithSingleWhenClauseInSubselect()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE g2.name WHEN 'admin' THEN 1 ELSE 2 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE g2.name WHEN 'admin' THEN 1 ELSE 2 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE c1_.name WHEN admin THEN 1 ELSE 2 END AS sclr2 FROM cms_groups c1_)"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testSimpleCaseWithMultipleWhenClauseInSubselect()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE g2.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
|
||||
"SELECT g FROM Doctrine\Tests\Models\CMS\CmsGroup g WHERE g.id IN (SELECT CASE g2.name WHEN 'admin' THEN 1 WHEN 'moderator' THEN 2 ELSE 3 END FROM Doctrine\Tests\Models\CMS\CmsGroup g2)",
|
||||
"SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_groups c0_ WHERE c0_.id IN (SELECT CASE c1_.name WHEN admin THEN 1 WHEN moderator THEN 2 ELSE 3 END AS sclr2 FROM cms_groups c1_)"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-1339
|
||||
*/
|
||||
public function testIdentityFunctionInSelectClause()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT IDENTITY(u.email) as email_id FROM Doctrine\Tests\Models\CMS\CmsUser u",
|
||||
"SELECT IDENTITY(u.email) as email_id FROM Doctrine\Tests\Models\CMS\CmsUser u",
|
||||
"SELECT c0_.email_id AS sclr0 FROM cms_users c0_"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-1339
|
||||
*/
|
||||
public function testIdentityFunctionDoesNotAcceptStateField()
|
||||
{
|
||||
$this->assertInvalidSqlGeneration(
|
||||
"SELECT IDENTITY(u.name) as name FROM Doctrine\Tests\Models\CMS\CmsUser u",
|
||||
"SELECT IDENTITY(u.name) as name FROM Doctrine\Tests\Models\CMS\CmsUser u",
|
||||
"Doctrine\ORM\Query\QueryException"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @group DDC-1389
|
||||
*/
|
||||
public function testInheritanceTypeJoinInRootClassWithDisabledForcePartialLoad()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p',
|
||||
'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 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 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 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 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 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 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 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 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 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 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 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 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)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1384
|
||||
*/
|
||||
public function testAliasDoesNotExceedPlatformDefinedLength()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT m FROM ' . __NAMESPACE__ . '\\DDC1384Model m',
|
||||
"SELECT d0_.aVeryLongIdentifierThatShouldBeShortenedByTheSQLWalker_fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo AS fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0 FROM DDC1384Model d0_"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-331
|
||||
* @group DDC-1384
|
||||
*/
|
||||
public function testIssue331()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'SELECT e.name FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
|
||||
'SELECT c0_.name AS name0 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id'
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @group DDC-1435
|
||||
*/
|
||||
public function testForeignKeyAsPrimaryKeySubselect()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
"SELECT s FROM Doctrine\Tests\Models\DDC117\DDC117Article s WHERE EXISTS (SELECT r FROM Doctrine\Tests\Models\DDC117\DDC117Reference r WHERE r.source = s)",
|
||||
"SELECT d0_.article_id AS article_id0, d0_.title AS title1 FROM DDC117Article d0_ WHERE EXISTS (SELECT d1_.source_id, d1_.target_id FROM DDC117Reference d1_ WHERE d1_.source_id = d0_.article_id)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1277,7 +1327,19 @@ class MyAbsFunction extends \Doctrine\ORM\Query\AST\Functions\FunctionNode
|
||||
$parser->match(\Doctrine\ORM\Query\Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
|
||||
|
||||
$parser->match(\Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC1384Model
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
protected $aVeryLongIdentifierThatShouldBeShortenedByTheSQLWalker_fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo;
|
||||
}
|
||||
|
@ -71,4 +71,88 @@ class SchemaValidatorTest extends \Doctrine\Tests\OrmTestCase
|
||||
));
|
||||
$this->validator->validateMapping();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1439
|
||||
*/
|
||||
public function testInvalidManyToManyJoinColumnSchema()
|
||||
{
|
||||
$class1 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity1');
|
||||
$class2 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity2');
|
||||
|
||||
$ce = $this->validator->validateClass($class1);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
"The inverse join columns of the many-to-many table 'Entity1Entity2' have to contain to ALL identifier columns of the target entity 'Doctrine\Tests\ORM\Tools\InvalidEntity2', however 'key4' are missing.",
|
||||
"The join columns of the many-to-many table 'Entity1Entity2' have to contain to ALL identifier columns of the source entity 'Doctrine\Tests\ORM\Tools\InvalidEntity1', however 'key2' are missing."
|
||||
),
|
||||
$ce
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1439
|
||||
*/
|
||||
public function testInvalidToOneJoinColumnSchema()
|
||||
{
|
||||
$class1 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity1');
|
||||
$class2 = $this->em->getClassMetadata(__NAMESPACE__ . '\InvalidEntity2');
|
||||
|
||||
$ce = $this->validator->validateClass($class2);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
"The referenced column name 'id' does not have a corresponding field with this column name on the class 'Doctrine\Tests\ORM\Tools\InvalidEntity1'.",
|
||||
"The join columns of the association 'assoc' have to match to ALL identifier columns of the source entity 'Doctrine\Tests\ORM\Tools\InvalidEntity2', however 'key3, key4' are missing."
|
||||
),
|
||||
$ce
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class InvalidEntity1
|
||||
{
|
||||
/**
|
||||
* @Id @Column
|
||||
*/
|
||||
protected $key1;
|
||||
/**
|
||||
* @Id @Column
|
||||
*/
|
||||
protected $key2;
|
||||
/**
|
||||
* @ManyToMany (targetEntity="InvalidEntity2")
|
||||
* @JoinTable (name="Entity1Entity2",
|
||||
* joinColumns={@JoinColumn(name="key1", referencedColumnName="key1")},
|
||||
* inverseJoinColumns={@JoinColumn(name="key3", referencedColumnName="key3")}
|
||||
* )
|
||||
*/
|
||||
protected $entity2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class InvalidEntity2
|
||||
{
|
||||
/**
|
||||
* @Id @Column
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $key3;
|
||||
|
||||
/**
|
||||
* @Id @Column
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $key4;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="InvalidEntity1")
|
||||
*/
|
||||
protected $assoc;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user