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
|
# EntityManager#getPartialReference() creates read-only entity
|
||||||
|
|
||||||
Entities returned from EntityManager#getPartialReference() are now marked as read-only if they
|
Entities returned from EntityManager#getPartialReference() are now marked as read-only if they
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
namespace Doctrine\ORM;
|
namespace Doctrine\ORM;
|
||||||
|
|
||||||
use Doctrine\DBAL\Types\Type,
|
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.
|
* Base contract for ORM queries. Base class for Query and NativeQuery.
|
||||||
@ -91,34 +92,15 @@ abstract class AbstractQuery
|
|||||||
protected $_hydrationMode = self::HYDRATE_OBJECT;
|
protected $_hydrationMode = self::HYDRATE_OBJECT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The locally set cache driver used for caching result sets of this query.
|
* @param \Doctrine\DBAL\Cache\QueryCacheProfile
|
||||||
*
|
|
||||||
* @var CacheDriver
|
|
||||||
*/
|
*/
|
||||||
protected $_resultCacheDriver;
|
protected $_queryCacheProfile;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var boolean Boolean value that indicates whether or not expire the result cache.
|
* @var boolean Boolean value that indicates whether or not expire the result cache.
|
||||||
*/
|
*/
|
||||||
protected $_expireResultCache = false;
|
protected $_expireResultCache = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int Result Cache lifetime.
|
|
||||||
*/
|
|
||||||
protected $_resultCacheTTL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
|
* 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
|
* @param Doctrine\Common\Cache\Cache $driver Cache driver
|
||||||
* @return Doctrine\ORM\AbstractQuery
|
* @return Doctrine\ORM\AbstractQuery
|
||||||
@ -270,9 +252,10 @@ abstract class AbstractQuery
|
|||||||
if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) {
|
if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) {
|
||||||
throw ORMException::invalidResultCacheDriver();
|
throw ORMException::invalidResultCacheDriver();
|
||||||
}
|
}
|
||||||
$this->_resultCacheDriver = $resultCacheDriver;
|
if ($this->_queryCacheProfile) {
|
||||||
if ($resultCacheDriver) {
|
$this->_queryCacheProfile = $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver);
|
||||||
$this->_useResultCache = true;
|
} else {
|
||||||
|
$this->_queryCacheProfile = new QueryCacheProfile(0, null, $resultCacheDriver);
|
||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -280,12 +263,13 @@ abstract class AbstractQuery
|
|||||||
/**
|
/**
|
||||||
* Returns the cache driver used for caching result sets.
|
* Returns the cache driver used for caching result sets.
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
* @return Doctrine\Common\Cache\Cache Cache driver
|
* @return Doctrine\Common\Cache\Cache Cache driver
|
||||||
*/
|
*/
|
||||||
public function getResultCacheDriver()
|
public function getResultCacheDriver()
|
||||||
{
|
{
|
||||||
if ($this->_resultCacheDriver) {
|
if ($this->_queryCacheProfile && $this->_queryCacheProfile->getResultCacheDriver()) {
|
||||||
return $this->_resultCacheDriver;
|
return $this->_queryCacheProfile->getResultCacheDriver();
|
||||||
} else {
|
} else {
|
||||||
return $this->_em->getConfiguration()->getResultCacheImpl();
|
return $this->_em->getConfiguration()->getResultCacheImpl();
|
||||||
}
|
}
|
||||||
@ -296,18 +280,17 @@ abstract class AbstractQuery
|
|||||||
* how long and which ID to use for the cache entry.
|
* how long and which ID to use for the cache entry.
|
||||||
*
|
*
|
||||||
* @param boolean $bool
|
* @param boolean $bool
|
||||||
* @param integer $timeToLive
|
* @param integer $lifetime
|
||||||
* @param string $resultCacheId
|
* @param string $resultCacheId
|
||||||
* @return Doctrine\ORM\AbstractQuery This query instance.
|
* @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 ($bool) {
|
||||||
if ($timeToLive) {
|
$this->setResultCacheLifetime($lifetime);
|
||||||
$this->setResultCacheLifetime($timeToLive);
|
$this->setResultCacheId($resultCacheId);
|
||||||
}
|
} else {
|
||||||
if ($resultCacheId) {
|
$this->_queryCacheProfile = null;
|
||||||
$this->_resultCacheId = $resultCacheId;
|
|
||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -315,27 +298,33 @@ abstract class AbstractQuery
|
|||||||
/**
|
/**
|
||||||
* Defines how long the result cache will be active before expire.
|
* 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.
|
* @return Doctrine\ORM\AbstractQuery This query instance.
|
||||||
*/
|
*/
|
||||||
public function setResultCacheLifetime($timeToLive)
|
public function setResultCacheLifetime($lifetime)
|
||||||
{
|
{
|
||||||
if ($timeToLive !== null) {
|
if ($lifetime === null) {
|
||||||
$timeToLive = (int) $timeToLive;
|
$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;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the lifetime of resultset cache.
|
* Retrieves the lifetime of resultset cache.
|
||||||
*
|
*
|
||||||
|
* @deprecated
|
||||||
* @return integer
|
* @return integer
|
||||||
*/
|
*/
|
||||||
public function getResultCacheLifetime()
|
public function getResultCacheLifetime()
|
||||||
{
|
{
|
||||||
return $this->_resultCacheTTL;
|
return $this->_queryCacheProfile ? $this->_queryCacheProfile->getLifetime() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -360,6 +349,14 @@ abstract class AbstractQuery
|
|||||||
return $this->_expireResultCache;
|
return $this->_expireResultCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return QueryCacheProfile
|
||||||
|
*/
|
||||||
|
public function getQueryCacheProfile()
|
||||||
|
{
|
||||||
|
return $this->_queryCacheProfile;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the default fetch mode of an association for this query.
|
* 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 array $params The query parameters.
|
||||||
* @param integer $hydrationMode The hydration mode to use.
|
* @param integer $hydrationMode The hydration mode to use.
|
||||||
* @return IterableResult
|
* @return \Doctrine\ORM\Internal\Hydration\IterableResult
|
||||||
*/
|
*/
|
||||||
public function iterate(array $params = array(), $hydrationMode = null)
|
public function iterate(array $params = array(), $hydrationMode = null)
|
||||||
{
|
{
|
||||||
@ -584,28 +581,6 @@ abstract class AbstractQuery
|
|||||||
$this->setParameters($params);
|
$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();
|
$stmt = $this->_doExecute();
|
||||||
|
|
||||||
if (is_numeric($stmt)) {
|
if (is_numeric($stmt)) {
|
||||||
@ -627,43 +602,23 @@ abstract class AbstractQuery
|
|||||||
*/
|
*/
|
||||||
public function setResultCacheId($id)
|
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;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the result cache id to use to store the result set cache entry.
|
* Get the result cache id to use to store the result set cache entry if set.
|
||||||
* Will return the configured id if it exists otherwise a hash will be
|
|
||||||
* automatically generated for you.
|
|
||||||
*
|
*
|
||||||
* @return array ($key, $hash)
|
* @deprecated
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function getResultCacheId()
|
public function getResultCacheId()
|
||||||
{
|
{
|
||||||
if ($this->_resultCacheId) {
|
return $this->_queryCacheProfile ? $this->_queryCacheProfile->getCacheKey() : null;
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -209,27 +209,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
|||||||
$this->_attributes['metadataDriverImpl'] : null;
|
$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).
|
* Gets the cache driver implementation that is used for the query cache (SQL cache).
|
||||||
*
|
*
|
||||||
|
@ -19,14 +19,16 @@
|
|||||||
|
|
||||||
namespace Doctrine\ORM\Event;
|
namespace Doctrine\ORM\Event;
|
||||||
|
|
||||||
use \Doctrine\Common\EventSubscriber;
|
use Doctrine\Common\EventSubscriber;
|
||||||
use \LogicException;
|
use LogicException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate events only for certain entities they are registered for.
|
* Delegate events only for certain entities they are registered for.
|
||||||
*
|
*
|
||||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
* @link www.doctrine-project.org
|
||||||
* @since 2.2
|
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||||
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
|
* @since 2.2
|
||||||
*/
|
*/
|
||||||
class EntityEventDelegator implements EventSubscriber
|
class EntityEventDelegator implements EventSubscriber
|
||||||
{
|
{
|
||||||
@ -54,17 +56,23 @@ class EntityEventDelegator implements EventSubscriber
|
|||||||
public function addEventListener($events, $entities, $listener)
|
public function addEventListener($events, $entities, $listener)
|
||||||
{
|
{
|
||||||
if ($this->frozen) {
|
if ($this->frozen) {
|
||||||
throw new LogicException("Cannot add event listeners after EntityEventDelegator::getSubscribedEvents() " .
|
throw new LogicException(
|
||||||
"is called once. This happens when you register the delegator with the event manager.");
|
"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
|
// 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) {
|
foreach ((array) $events as $event) {
|
||||||
// Overrides listener if a previous one was associated already
|
// Overrides listener if a previous one was associated already
|
||||||
// Prevents duplicate listeners on same event (same instance only)
|
// 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.
|
* interested in and added as a listener for these events.
|
||||||
*
|
*
|
||||||
* @param Doctrine\Common\EventSubscriber $subscriber The subscriber.
|
* @param Doctrine\Common\EventSubscriber $subscriber The subscriber.
|
||||||
|
* @param array $entities
|
||||||
*/
|
*/
|
||||||
public function addEventSubscriber(EventSubscriber $subscriber, $entities)
|
public function addEventSubscriber(EventSubscriber $subscriber, $entities)
|
||||||
{
|
{
|
||||||
@ -87,24 +96,27 @@ class EntityEventDelegator implements EventSubscriber
|
|||||||
public function getSubscribedEvents()
|
public function getSubscribedEvents()
|
||||||
{
|
{
|
||||||
$this->frozen = true;
|
$this->frozen = true;
|
||||||
|
|
||||||
return array_keys($this->listeners);
|
return array_keys($this->listeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate the event to an appropriate listener
|
* Delegate the event to an appropriate listener
|
||||||
*
|
*
|
||||||
* @param $eventName
|
* @param string $eventName
|
||||||
* @param $event
|
* @param array $args
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __call($eventName, $args)
|
public function __call($eventName, $args)
|
||||||
{
|
{
|
||||||
$event = $args[0];
|
$event = $args[0];
|
||||||
|
|
||||||
foreach ($this->listeners[$eventName] AS $listenerData) {
|
foreach ($this->listeners[$eventName] AS $listenerData) {
|
||||||
$class = get_class($event->getEntity());
|
$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;
|
namespace Doctrine\ORM\Event;
|
||||||
|
|
||||||
|
use Doctrine\Common\EventArgs;
|
||||||
|
use Doctrine\ORM\EntityManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions
|
* Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions
|
||||||
* of entities.
|
* of entities.
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @link www.doctrine-project.org
|
||||||
|
* @since 2.0
|
||||||
* @author Roman Borschel <roman@code-factory.de>
|
* @author Roman Borschel <roman@code-factory.de>
|
||||||
* @author Benjamin Eberlei <kontakt@beberlei.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
|
* @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->entity = $entity;
|
||||||
$this->_em = $em;
|
$this->em = $em;
|
||||||
}
|
|
||||||
|
|
||||||
public function getEntity()
|
|
||||||
{
|
|
||||||
return $this->_entity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return EntityManager
|
* Retireve associated Entity.
|
||||||
|
*
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
public function getEntity()
|
||||||
|
{
|
||||||
|
return $this->entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve associated EntityManager.
|
||||||
|
*
|
||||||
|
* @return Doctrine\ORM\EntityManager
|
||||||
*/
|
*/
|
||||||
public function getEntityManager()
|
public function getEntityManager()
|
||||||
{
|
{
|
||||||
return $this->_em;
|
return $this->em;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +1,25 @@
|
|||||||
<?php
|
<?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;
|
namespace Doctrine\ORM\Event;
|
||||||
|
|
||||||
use Doctrine\Common\EventArgs;
|
use Doctrine\Common\EventArgs;
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||||
use Doctrine\ORM\EntityManager;
|
use Doctrine\ORM\EntityManager;
|
||||||
|
|
||||||
@ -11,32 +27,36 @@ use Doctrine\ORM\EntityManager;
|
|||||||
* Class that holds event arguments for a loadMetadata event.
|
* Class that holds event arguments for a loadMetadata event.
|
||||||
*
|
*
|
||||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
class LoadClassMetadataEventArgs extends EventArgs
|
class LoadClassMetadataEventArgs extends EventArgs
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var ClassMetadata
|
* @var Doctrine\ORM\Mapping\ClassMetadata
|
||||||
*/
|
*/
|
||||||
private $classMetadata;
|
private $classMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var EntityManager
|
* @var Doctrine\ORM\EntityManager
|
||||||
*/
|
*/
|
||||||
private $em;
|
private $em;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ClassMetadataInfo $classMetadata
|
* Constructor.
|
||||||
* @param EntityManager $em
|
*
|
||||||
|
* @param Doctrine\ORM\Mapping\ClassMetadataInfo $classMetadata
|
||||||
|
* @param Doctrine\ORM\EntityManager $em
|
||||||
*/
|
*/
|
||||||
public function __construct(ClassMetadataInfo $classMetadata, EntityManager $em)
|
public function __construct(ClassMetadataInfo $classMetadata, EntityManager $em)
|
||||||
{
|
{
|
||||||
$this->classMetadata = $classMetadata;
|
$this->classMetadata = $classMetadata;
|
||||||
$this->em = $em;
|
$this->em = $em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return ClassMetadataInfo
|
* Retrieve associated ClassMetadata.
|
||||||
|
*
|
||||||
|
* @return Doctrine\ORM\Mapping\ClassMetadataInfo
|
||||||
*/
|
*/
|
||||||
public function getClassMetadata()
|
public function getClassMetadata()
|
||||||
{
|
{
|
||||||
@ -44,7 +64,9 @@ class LoadClassMetadataEventArgs extends EventArgs
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return EntityManager
|
* Retrieve associated EntityManager.
|
||||||
|
*
|
||||||
|
* @return Doctrine\ORM\EntityManager
|
||||||
*/
|
*/
|
||||||
public function getEntityManager()
|
public function getEntityManager()
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* This software consists of voluntary contributions made by many individuals
|
* This software consists of voluntary contributions made by many individuals
|
||||||
* and is licensed under the LGPL. For more information, see
|
* and is licensed under the LGPL. For more information, see
|
||||||
* <http://www.doctrine-project.org>.
|
* <http://www.doctrine-project.org>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Doctrine\ORM\Event;
|
namespace Doctrine\ORM\Event;
|
||||||
|
|
||||||
@ -23,16 +23,15 @@ namespace Doctrine\ORM\Event;
|
|||||||
* Provides event arguments for the onClear event.
|
* Provides event arguments for the onClear event.
|
||||||
*
|
*
|
||||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
* @link www.doctrine-project.com
|
* @link www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Revision$
|
|
||||||
* @author Roman Borschel <roman@code-factory.de>
|
* @author Roman Borschel <roman@code-factory.de>
|
||||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||||
*/
|
*/
|
||||||
class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var \Doctrine\ORM\EntityManager
|
* @var Doctrine\ORM\EntityManager
|
||||||
*/
|
*/
|
||||||
private $em;
|
private $em;
|
||||||
|
|
||||||
@ -42,16 +41,21 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
|||||||
private $entityClass;
|
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)
|
public function __construct($em, $entityClass = null)
|
||||||
{
|
{
|
||||||
$this->em = $em;
|
$this->em = $em;
|
||||||
$this->entityClass = $entityClass;
|
$this->entityClass = $entityClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Doctrine\ORM\EntityManager
|
* Retrieve associated EntityManager.
|
||||||
|
*
|
||||||
|
* @return Doctrine\ORM\EntityManager
|
||||||
*/
|
*/
|
||||||
public function getEntityManager()
|
public function getEntityManager()
|
||||||
{
|
{
|
||||||
@ -75,6 +79,6 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
|||||||
*/
|
*/
|
||||||
public function clearsAllEntities()
|
public function clearsAllEntities()
|
||||||
{
|
{
|
||||||
return $this->entityClass === null;
|
return ($this->entityClass === null);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,37 +21,45 @@
|
|||||||
|
|
||||||
namespace Doctrine\ORM\Event;
|
namespace Doctrine\ORM\Event;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides event arguments for the preFlush event.
|
* Provides event arguments for the preFlush event.
|
||||||
*
|
*
|
||||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
* @link www.doctrine-project.com
|
* @link www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Revision$
|
|
||||||
* @author Roman Borschel <roman@code-factory.de>
|
* @author Roman Borschel <roman@code-factory.de>
|
||||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||||
*/
|
*/
|
||||||
class OnFlushEventArgs extends \Doctrine\Common\EventArgs
|
class OnFlushEventArgs extends \Doctrine\Common\EventArgs
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var EntityManager
|
* @var Doctirne\ORM\EntityManager
|
||||||
*/
|
*/
|
||||||
private $_em;
|
private $em;
|
||||||
|
|
||||||
//private $_entitiesToPersist = array();
|
//private $entitiesToPersist = array();
|
||||||
//private $_entitiesToRemove = 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()
|
public function getEntityManager()
|
||||||
{
|
{
|
||||||
return $this->_em;
|
return $this->em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -17,9 +17,10 @@
|
|||||||
* This software consists of voluntary contributions made by many individuals
|
* This software consists of voluntary contributions made by many individuals
|
||||||
* and is licensed under the LGPL. For more information, see
|
* and is licensed under the LGPL. For more information, see
|
||||||
* <http://www.doctrine-project.org>.
|
* <http://www.doctrine-project.org>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Doctrine\ORM\Event;
|
namespace Doctrine\ORM\Event;
|
||||||
|
|
||||||
use Doctrine\ORM\EntityManager;
|
use Doctrine\ORM\EntityManager;
|
||||||
use Doctrine\Common\EventArgs;
|
use Doctrine\Common\EventArgs;
|
||||||
|
|
||||||
@ -27,20 +28,21 @@ use Doctrine\Common\EventArgs;
|
|||||||
* Provides event arguments for the postFlush event.
|
* Provides event arguments for the postFlush event.
|
||||||
*
|
*
|
||||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
* @link www.doctrine-project.com
|
* @link www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Revision$
|
|
||||||
* @author Daniel Freudenberger <df@rebuy.de>
|
* @author Daniel Freudenberger <df@rebuy.de>
|
||||||
*/
|
*/
|
||||||
class PostFlushEventArgs extends EventArgs
|
class PostFlushEventArgs extends EventArgs
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var EntityManager
|
* @var Doctrine\ORM\EntityManager
|
||||||
*/
|
*/
|
||||||
private $em;
|
private $em;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param EntityManager $em
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param Doctrine\ORM\EntityManager $em
|
||||||
*/
|
*/
|
||||||
public function __construct(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()
|
public function getEntityManager()
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,23 @@
|
|||||||
<?php
|
<?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;
|
namespace Doctrine\ORM\Event;
|
||||||
|
|
||||||
@ -8,42 +27,50 @@ use Doctrine\Common\EventArgs,
|
|||||||
/**
|
/**
|
||||||
* Class that holds event arguments for a preInsert/preUpdate event.
|
* Class that holds event arguments for a preInsert/preUpdate event.
|
||||||
*
|
*
|
||||||
|
* @author Guilherme Blanco <guilehrmeblanco@hotmail.com>
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
class PreUpdateEventArgs extends LifecycleEventArgs
|
class PreUpdateEventArgs extends LifecycleEventArgs
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $_entityChangeSet;
|
private $entityChangeSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param object $entity
|
* @param object $entity
|
||||||
* @param EntityManager $em
|
* @param Doctrine\ORM\EntityManager $em
|
||||||
* @param array $changeSet
|
* @param array $changeSet
|
||||||
*/
|
*/
|
||||||
public function __construct($entity, $em, array &$changeSet)
|
public function __construct($entity, EntityManager $em, array &$changeSet)
|
||||||
{
|
{
|
||||||
parent::__construct($entity, $em);
|
parent::__construct($entity, $em);
|
||||||
$this->_entityChangeSet = &$changeSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEntityChangeSet()
|
$this->entityChangeSet = &$changeSet;
|
||||||
{
|
|
||||||
return $this->_entityChangeSet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Field has a changeset?
|
* Retrieve entity changeset.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getEntityChangeSet()
|
||||||
|
{
|
||||||
|
return $this->entityChangeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if field has a changeset.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function hasChangedField($field)
|
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)
|
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)
|
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)
|
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])) {
|
if ( ! isset($this->entityChangeSet[$field])) {
|
||||||
throw new \InvalidArgumentException(
|
throw new \InvalidArgumentException(sprintf(
|
||||||
"Field '".$field."' is not a valid field of the entity ".
|
'Field "%s" is not a valid field of the entity "%s" in PreUpdateEventArgs.',
|
||||||
"'".get_class($this->getEntity())."' in PreUpdateEventArgs."
|
$field,
|
||||||
);
|
get_class($this->getEntity())
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
namespace Doctrine\ORM\Id;
|
namespace Doctrine\ORM\Id;
|
||||||
|
|
||||||
use Doctrine\ORM\EntityManager;
|
use Doctrine\ORM\EntityManager;
|
||||||
|
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||||
use Doctrine\ORM\ORMException;
|
use Doctrine\ORM\ORMException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,44 +43,27 @@ class AssignedGenerator extends AbstractIdGenerator
|
|||||||
*/
|
*/
|
||||||
public function generate(EntityManager $em, $entity)
|
public function generate(EntityManager $em, $entity)
|
||||||
{
|
{
|
||||||
$class = $em->getClassMetadata(get_class($entity));
|
$class = $em->getClassMetadata(get_class($entity));
|
||||||
|
$idFields = $class->getIdentifierFieldNames();
|
||||||
$identifier = array();
|
$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.
|
foreach ($idFields as $idField) {
|
||||||
$identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value));
|
|
||||||
} else {
|
|
||||||
$identifier[$idField] = $value;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw ORMException::entityMissingAssignedIdForField($entity, $idField);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$idField = $class->identifier[0];
|
|
||||||
$value = $class->reflFields[$idField]->getValue($entity);
|
$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.
|
if ( ! isset($value)) {
|
||||||
$identifier[$idField] = current($em->getUnitOfWork()->getEntityIdentifier($value));
|
|
||||||
} else {
|
|
||||||
$identifier[$idField] = $value;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw ORMException::entityMissingAssignedIdForField($entity, $idField);
|
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;
|
return $identifier;
|
||||||
|
@ -369,10 +369,7 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
$this->_resultPointers[$dqlAlias] = $reflFieldValue[$index];
|
$this->_resultPointers[$dqlAlias] = $reflFieldValue[$index];
|
||||||
}
|
}
|
||||||
} else if ( ! $reflField->getValue($parentObject)) {
|
} else if ( ! $reflField->getValue($parentObject)) {
|
||||||
$coll = new PersistentCollection($this->_em, $this->_ce[$entityName], new ArrayCollection);
|
$reflFieldValue = $this->_initRelatedCollection($parentObject, $parentClass, $relationField);
|
||||||
$coll->setOwner($parentObject, $relation);
|
|
||||||
$reflField->setValue($parentObject, $coll);
|
|
||||||
$this->_uow->setOriginalEntityProperty($oid, $relationField, $coll);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// PATH B: Single-valued association
|
// PATH B: Single-valued association
|
||||||
|
@ -1111,23 +1111,23 @@ class ClassMetadataInfo implements ClassMetadata
|
|||||||
*/
|
*/
|
||||||
public function getIdentifierColumnNames()
|
public function getIdentifierColumnNames()
|
||||||
{
|
{
|
||||||
if ($this->isIdentifierComposite) {
|
$columnNames = array();
|
||||||
$columnNames = array();
|
|
||||||
foreach ($this->identifier as $idField) {
|
foreach ($this->identifier as $idProperty) {
|
||||||
if (isset($this->associationMappings[$idField])) {
|
if (isset($this->fieldMappings[$idProperty])) {
|
||||||
// no composite pk as fk entity assumption:
|
$columnNames[] = $this->fieldMappings[$idProperty]['columnName'];
|
||||||
$columnNames[] = $this->associationMappings[$idField]['joinColumns'][0]['name'];
|
|
||||||
} else {
|
continue;
|
||||||
$columnNames[] = $this->fieldMappings[$idField]['columnName'];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $columnNames;
|
|
||||||
} else if(isset($this->fieldMappings[$this->identifier[0]])) {
|
// Association defined as Id field
|
||||||
return array($this->fieldMappings[$this->identifier[0]]['columnName']);
|
$joinColumns = $this->associationMappings[$idProperty]['joinColumns'];
|
||||||
} else {
|
$assocColumnNames = array_map(function ($joinColumn) { return $joinColumn['name']; }, $joinColumns);
|
||||||
// no composite pk as fk entity assumption:
|
|
||||||
return array($this->associationMappings[$this->identifier[0]]['joinColumns'][0]['name']);
|
$columnNames = array_merge($columnNames, $assocColumnNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $columnNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1904,6 +1904,42 @@ class ClassMetadataInfo implements ClassMetadata
|
|||||||
return $this->name;
|
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
|
* Gets the (possibly quoted) column name of a mapped field for safe use
|
||||||
* in an SQL statement.
|
* in an SQL statement.
|
||||||
@ -1914,7 +1950,9 @@ class ClassMetadataInfo implements ClassMetadata
|
|||||||
*/
|
*/
|
||||||
public function getQuotedColumnName($field, $platform)
|
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'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -327,6 +327,8 @@ class XmlDriver extends AbstractFileDriver
|
|||||||
|
|
||||||
if (isset($oneToManyElement['index-by'])) {
|
if (isset($oneToManyElement['index-by'])) {
|
||||||
$mapping['indexBy'] = (string)$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);
|
$metadata->mapOneToMany($mapping);
|
||||||
@ -432,8 +434,10 @@ class XmlDriver extends AbstractFileDriver
|
|||||||
$mapping['orderBy'] = $orderBy;
|
$mapping['orderBy'] = $orderBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($manyToManyElement->{'index-by'})) {
|
if (isset($manyToManyElement['index-by'])) {
|
||||||
$mapping['indexBy'] = (string)$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);
|
$metadata->mapManyToMany($mapping);
|
||||||
|
@ -57,17 +57,17 @@ final class NativeQuery extends AbstractQuery
|
|||||||
*/
|
*/
|
||||||
protected function _doExecute()
|
protected function _doExecute()
|
||||||
{
|
{
|
||||||
$stmt = $this->_em->getConnection()->prepare($this->_sql);
|
|
||||||
$params = $this->_params;
|
$params = $this->_params;
|
||||||
foreach ($params as $key => $value) {
|
$types = $this->_paramTypes;
|
||||||
if (isset($this->_paramTypes[$key])) {
|
if ($params) {
|
||||||
$stmt->bindValue($key, $value, $this->_paramTypes[$key]);
|
if (is_int(key($params))) {
|
||||||
} else {
|
ksort($params);
|
||||||
$stmt->bindValue($key, $value);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -468,7 +468,7 @@ final class PersistentCollection implements Collection
|
|||||||
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
|
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
|
||||||
return $this->em->getUnitOfWork()
|
return $this->em->getUnitOfWork()
|
||||||
->getCollectionPersister($this->association)
|
->getCollectionPersister($this->association)
|
||||||
->count($this) + $this->coll->count();
|
->count($this) + ($this->isDirty ? $this->coll->count() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
@ -672,7 +672,10 @@ final class PersistentCollection implements Collection
|
|||||||
*/
|
*/
|
||||||
public function slice($offset, $length = null)
|
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()
|
return $this->em->getUnitOfWork()
|
||||||
->getCollectionPersister($this->association)
|
->getCollectionPersister($this->association)
|
||||||
->slice($this, $offset, $length);
|
->slice($this, $offset, $length);
|
||||||
|
@ -62,7 +62,7 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
|||||||
{
|
{
|
||||||
$columnName = $class->columnNames[$field];
|
$columnName = $class->columnNames[$field];
|
||||||
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
|
$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);
|
$this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name);
|
||||||
|
|
||||||
return $sql . ' AS ' . $columnAlias;
|
return $sql . ' AS ' . $columnAlias;
|
||||||
@ -70,9 +70,8 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
|
|||||||
|
|
||||||
protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className)
|
protected function getSelectJoinColumnSQL($tableAlias, $joinColumnName, $className)
|
||||||
{
|
{
|
||||||
$columnAlias = $joinColumnName . $this->_sqlAliasCounter++;
|
$columnAlias = $this->getSQLColumnAlias($joinColumnName);
|
||||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
$this->_rsm->addMetaResult('r', $columnAlias, $joinColumnName);
|
||||||
$this->_rsm->addMetaResult('r', $resultColumnName, $joinColumnName);
|
|
||||||
|
|
||||||
return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias;
|
return $tableAlias . '.' . $joinColumnName . ' AS ' . $columnAlias;
|
||||||
}
|
}
|
||||||
|
@ -1001,7 +1001,6 @@ class BasicEntityPersister
|
|||||||
$columnList .= $assoc2ColumnSQL;
|
$columnList .= $assoc2ColumnSQL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$first = true;
|
$first = true;
|
||||||
|
|
||||||
if ($assoc['isOwningSide']) {
|
if ($assoc['isOwningSide']) {
|
||||||
@ -1012,7 +1011,6 @@ class BasicEntityPersister
|
|||||||
if ( ! $first) {
|
if ( ! $first) {
|
||||||
$this->_selectJoinSql .= ' AND ';
|
$this->_selectJoinSql .= ' AND ';
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
|
$this->_selectJoinSql .= $this->_getSQLTableAlias($assoc['sourceEntity']) . '.' . $sourceCol . ' = '
|
||||||
. $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.' . $targetCol;
|
. $this->_getSQLTableAlias($assoc['targetEntity'], $assocAlias) . '.' . $targetCol;
|
||||||
$first = false;
|
$first = false;
|
||||||
@ -1061,8 +1059,7 @@ class BasicEntityPersister
|
|||||||
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
|
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
|
||||||
if ($columnList) $columnList .= ', ';
|
if ($columnList) $columnList .= ', ';
|
||||||
|
|
||||||
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
|
$resultColumnName = $this->getSQLColumnAlias($srcColumn);
|
||||||
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
|
|
||||||
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
|
$columnList .= $this->_getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) )
|
||||||
. '.' . $srcColumn . ' AS ' . $resultColumnName;
|
. '.' . $srcColumn . ' AS ' . $resultColumnName;
|
||||||
$this->_rsm->addMetaResult($alias, $resultColumnName, $srcColumn, isset($assoc['id']) && $assoc['id'] === true);
|
$this->_rsm->addMetaResult($alias, $resultColumnName, $srcColumn, isset($assoc['id']) && $assoc['id'] === true);
|
||||||
@ -1181,10 +1178,9 @@ class BasicEntityPersister
|
|||||||
*/
|
*/
|
||||||
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
|
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
|
||||||
{
|
{
|
||||||
$columnName = $class->columnNames[$field];
|
|
||||||
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
|
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
|
||||||
. '.' . $class->getQuotedColumnName($field, $this->_platform);
|
. '.' . $class->getQuotedColumnName($field, $this->_platform);
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
|
$columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
|
||||||
|
|
||||||
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
|
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
|
||||||
|
|
||||||
@ -1493,8 +1489,8 @@ class BasicEntityPersister
|
|||||||
$criteria = array_merge($criteria, $extraConditions);
|
$criteria = array_merge($criteria, $extraConditions);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = 'SELECT 1'
|
$sql = 'SELECT 1 '
|
||||||
. ' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($this->_class->name)
|
. $this->getLockTablesSql()
|
||||||
. ' WHERE ' . $this->_getSelectConditionSQL($criteria);
|
. ' WHERE ' . $this->_getSelectConditionSQL($criteria);
|
||||||
|
|
||||||
list($params, $types) = $this->expandParameters($criteria);
|
list($params, $types) = $this->expandParameters($criteria);
|
||||||
@ -1519,4 +1515,19 @@ class BasicEntityPersister
|
|||||||
|
|
||||||
return 'INNER JOIN';
|
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())
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,6 +232,9 @@ final class Query extends AbstractQuery
|
|||||||
protected function _doExecute()
|
protected function _doExecute()
|
||||||
{
|
{
|
||||||
$executor = $this->_parse()->getSqlExecutor();
|
$executor = $this->_parse()->getSqlExecutor();
|
||||||
|
if ($this->_queryCacheProfile) {
|
||||||
|
$executor->setQueryCacheProfile($this->_queryCacheProfile);
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare parameters
|
// Prepare parameters
|
||||||
$paramMappings = $this->_parserResult->getParameterMappings();
|
$paramMappings = $this->_parserResult->getParameterMappings();
|
||||||
@ -523,7 +526,7 @@ final class Query extends AbstractQuery
|
|||||||
*
|
*
|
||||||
* @param array $params The query parameters.
|
* @param array $params The query parameters.
|
||||||
* @param integer $hydrationMode The hydration mode to use.
|
* @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)
|
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
/*
|
/*
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
@ -22,6 +20,7 @@
|
|||||||
namespace Doctrine\ORM\Query\Exec;
|
namespace Doctrine\ORM\Query\Exec;
|
||||||
|
|
||||||
use Doctrine\DBAL\Connection;
|
use Doctrine\DBAL\Connection;
|
||||||
|
use Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for SQL statement executors.
|
* Base class for SQL statement executors.
|
||||||
@ -34,8 +33,16 @@ use Doctrine\DBAL\Connection;
|
|||||||
*/
|
*/
|
||||||
abstract class AbstractSqlExecutor
|
abstract class AbstractSqlExecutor
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
protected $_sqlStatements;
|
protected $_sqlStatements;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var QueryCacheProfile
|
||||||
|
*/
|
||||||
|
protected $queryCacheProfile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the SQL statements that are executed by the executor.
|
* Gets the SQL statements that are executed by the executor.
|
||||||
*
|
*
|
||||||
@ -46,11 +53,17 @@ abstract class AbstractSqlExecutor
|
|||||||
return $this->_sqlStatements;
|
return $this->_sqlStatements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setQueryCacheProfile(QueryCacheProfile $qcp)
|
||||||
|
{
|
||||||
|
$this->queryCacheProfile = $qcp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes all sql statements.
|
* Executes all sql statements.
|
||||||
*
|
*
|
||||||
* @param Doctrine\DBAL\Connection $conn The database connection that is used to execute the queries.
|
* @param Doctrine\DBAL\Connection $conn The database connection that is used to execute the queries.
|
||||||
* @param array $params The parameters.
|
* @param array $params The parameters.
|
||||||
|
* @param array $types The parameter types.
|
||||||
* @return Doctrine\DBAL\Driver\Statement
|
* @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
|
<?php
|
||||||
/*
|
/*
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* 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
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
* @link http://www.doctrine-project.org
|
* @link http://www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Revision$
|
|
||||||
*/
|
*/
|
||||||
class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
||||||
{
|
{
|
||||||
@ -102,11 +99,7 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes all SQL statements.
|
* {@inheritDoc}
|
||||||
*
|
|
||||||
* @param Doctrine\DBAL\Connection $conn The database connection that is used to execute the queries.
|
|
||||||
* @param array $params The parameters.
|
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
public function execute(Connection $conn, array $params, array $types)
|
public function execute(Connection $conn, array $params, array $types)
|
||||||
{
|
{
|
||||||
|
@ -141,11 +141,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes all SQL statements.
|
* {@inheritDoc}
|
||||||
*
|
|
||||||
* @param Connection $conn The database connection that is used to execute the queries.
|
|
||||||
* @param array $params The parameters.
|
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
public function execute(Connection $conn, array $params, array $types)
|
public function execute(Connection $conn, array $params, array $types)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
/*
|
/*
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* 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
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* @version $Revision$
|
|
||||||
* @link www.doctrine-project.org
|
* @link www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
@ -41,8 +38,11 @@ class SingleSelectExecutor extends AbstractSqlExecutor
|
|||||||
$this->_sqlStatements = $sqlWalker->walkSelectStatement($AST);
|
$this->_sqlStatements = $sqlWalker->walkSelectStatement($AST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
public function execute(Connection $conn, array $params, array $types)
|
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
|
<?php
|
||||||
/*
|
/*
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* 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
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* @version $Revision$
|
|
||||||
* @link www.doctrine-project.org
|
* @link www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor.
|
* @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor.
|
||||||
@ -46,6 +43,9 @@ class SingleTableDeleteUpdateExecutor extends AbstractSqlExecutor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
public function execute(Connection $conn, array $params, array $types)
|
public function execute(Connection $conn, array $params, array $types)
|
||||||
{
|
{
|
||||||
return $conn->executeUpdate($this->_sqlStatements, $params, $types);
|
return $conn->executeUpdate($this->_sqlStatements, $params, $types);
|
||||||
|
@ -57,7 +57,7 @@ abstract class Base
|
|||||||
|
|
||||||
public function add($arg)
|
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 we decide to keep Expr\Base instances, we can use this check
|
||||||
if ( ! is_string($arg)) {
|
if ( ! is_string($arg)) {
|
||||||
$class = get_class($arg);
|
$class = get_class($arg);
|
||||||
|
@ -86,20 +86,22 @@ class ResultSetMappingBuilder extends ResultSetMapping
|
|||||||
if (isset($renamedColumns[$columnName])) {
|
if (isset($renamedColumns[$columnName])) {
|
||||||
$columnName = $renamedColumns[$columnName];
|
$columnName = $renamedColumns[$columnName];
|
||||||
}
|
}
|
||||||
|
$columnName = $platform->getSQLResultCasing($columnName);
|
||||||
if (isset($this->fieldMappings[$columnName])) {
|
if (isset($this->fieldMappings[$columnName])) {
|
||||||
throw new \InvalidArgumentException("The column '$columnName' conflicts with another column in the mapper.");
|
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) {
|
foreach ($classMetadata->associationMappings AS $associationMapping) {
|
||||||
if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
|
if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
|
||||||
foreach ($associationMapping['joinColumns'] AS $joinColumn) {
|
foreach ($associationMapping['joinColumns'] AS $joinColumn) {
|
||||||
$columnName = $joinColumn['name'];
|
$columnName = $joinColumn['name'];
|
||||||
$renamedColumnName = isset($renamedColumns[$columnName]) ? $renamedColumns[$columnName] : $columnName;
|
$renamedColumnName = isset($renamedColumns[$columnName]) ? $renamedColumns[$columnName] : $columnName;
|
||||||
|
$renamedColumnName = $platform->getSQLResultCasing($renamedColumnName);
|
||||||
if (isset($this->metaMappings[$renamedColumnName])) {
|
if (isset($this->metaMappings[$renamedColumnName])) {
|
||||||
throw new \InvalidArgumentException("The column '$renamedColumnName' conflicts with another column in the mapper.");
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,32 +157,24 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function getExecutor($AST)
|
public function getExecutor($AST)
|
||||||
{
|
{
|
||||||
$isDeleteStatement = $AST instanceof AST\DeleteStatement;
|
switch (true) {
|
||||||
$isUpdateStatement = $AST instanceof AST\UpdateStatement;
|
case ($AST instanceof AST\DeleteStatement):
|
||||||
|
$primaryClass = $this->_em->getClassMetadata($AST->deleteClause->abstractSchemaName);
|
||||||
|
|
||||||
if ($isDeleteStatement) {
|
return ($primaryClass->isInheritanceTypeJoined())
|
||||||
$primaryClass = $this->_em->getClassMetadata(
|
? new Exec\MultiTableDeleteExecutor($AST, $this)
|
||||||
$AST->deleteClause->abstractSchemaName
|
: new Exec\SingleTableDeleteUpdateExecutor($AST, $this);
|
||||||
);
|
|
||||||
|
|
||||||
if ($primaryClass->isInheritanceTypeJoined()) {
|
case ($AST instanceof AST\UpdateStatement):
|
||||||
return new Exec\MultiTableDeleteExecutor($AST, $this);
|
$primaryClass = $this->_em->getClassMetadata($AST->updateClause->abstractSchemaName);
|
||||||
} else {
|
|
||||||
return new Exec\SingleTableDeleteUpdateExecutor($AST, $this);
|
|
||||||
}
|
|
||||||
} else if ($isUpdateStatement) {
|
|
||||||
$primaryClass = $this->_em->getClassMetadata(
|
|
||||||
$AST->updateClause->abstractSchemaName
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($primaryClass->isInheritanceTypeJoined()) {
|
return ($primaryClass->isInheritanceTypeJoined())
|
||||||
return new Exec\MultiTableUpdateExecutor($AST, $this);
|
? new Exec\MultiTableUpdateExecutor($AST, $this)
|
||||||
} else {
|
: new Exec\SingleTableDeleteUpdateExecutor($AST, $this);
|
||||||
return new Exec\SingleTableDeleteUpdateExecutor($AST, $this);
|
|
||||||
}
|
default:
|
||||||
|
return new Exec\SingleSelectExecutor($AST, $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Exec\SingleSelectExecutor($AST, $this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -229,7 +221,11 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function getSQLColumnAlias($columnName)
|
public function getSQLColumnAlias($columnName)
|
||||||
{
|
{
|
||||||
return $columnName . $this->_aliasCounter++;
|
// 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->_aliasCounter++, -$this->_platform->getMaxIdentifierLength())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,10 +252,9 @@ class SqlWalker implements TreeWalker
|
|||||||
$sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
$sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||||
$first = true;
|
$first = true;
|
||||||
|
|
||||||
foreach ($class->identifier as $idField) {
|
foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
|
||||||
if ($first) $first = false; else $sql .= ' AND ';
|
if ($first) $first = false; else $sql .= ' AND ';
|
||||||
|
|
||||||
$columnName = $class->getQuotedColumnName($idField, $this->_platform);
|
|
||||||
$sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
|
$sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -272,10 +267,9 @@ class SqlWalker implements TreeWalker
|
|||||||
$sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
$sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
|
||||||
$first = true;
|
$first = true;
|
||||||
|
|
||||||
foreach ($class->identifier as $idField) {
|
foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
|
||||||
if ($first) $first = false; else $sql .= ' AND ';
|
if ($first) $first = false; else $sql .= ' AND ';
|
||||||
|
|
||||||
$columnName = $class->getQuotedColumnName($idField, $this->_platform);
|
|
||||||
$sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
|
$sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -535,7 +529,6 @@ class SqlWalker implements TreeWalker
|
|||||||
|
|
||||||
$sqlSelectExpressions[] = $tblAlias . '.' . $discrColumn['name'] . ' AS ' . $columnAlias;
|
$sqlSelectExpressions[] = $tblAlias . '.' . $discrColumn['name'] . ' AS ' . $columnAlias;
|
||||||
|
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
|
||||||
$this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias);
|
$this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias);
|
||||||
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']);
|
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']);
|
||||||
|
|
||||||
@ -556,8 +549,7 @@ class SqlWalker implements TreeWalker
|
|||||||
|
|
||||||
$sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
|
$sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
|
||||||
|
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true));
|
||||||
$this->_rsm->addMetaResult($dqlAlias, $this->_platform->getSQLResultCasing($columnAlias), $srcColumn, (isset($assoc['id']) && $assoc['id'] === true));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -574,8 +566,7 @@ class SqlWalker implements TreeWalker
|
|||||||
|
|
||||||
$sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
|
$sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
|
||||||
|
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true));
|
||||||
$this->_rsm->addMetaResult($dqlAlias, $this->_platform->getSQLResultCasing($columnAlias), $srcColumn, (isset($assoc['id']) && $assoc['id'] === true));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -989,24 +980,19 @@ class SqlWalker implements TreeWalker
|
|||||||
$qComp = $this->_queryComponents[$dqlAlias];
|
$qComp = $this->_queryComponents[$dqlAlias];
|
||||||
$class = $qComp['metadata'];
|
$class = $qComp['metadata'];
|
||||||
|
|
||||||
if ( ! $selectExpression->fieldIdentificationVariable) {
|
$resultAlias = ( ! $selectExpression->fieldIdentificationVariable)
|
||||||
$resultAlias = $fieldName;
|
? $fieldName
|
||||||
} else {
|
: $selectExpression->fieldIdentificationVariable;
|
||||||
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($class->isInheritanceTypeJoined()) {
|
$tableName = ($class->isInheritanceTypeJoined())
|
||||||
$tableName = $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName);
|
? $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName)
|
||||||
} else {
|
: $class->getTableName();
|
||||||
$tableName = $class->getTableName();
|
|
||||||
}
|
|
||||||
|
|
||||||
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
|
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
|
||||||
$columnName = $class->getQuotedColumnName($fieldName, $this->_platform);
|
$columnName = $class->getQuotedColumnName($fieldName, $this->_platform);
|
||||||
|
|
||||||
$columnAlias = $this->getSQLColumnAlias($columnName);
|
$columnAlias = $this->getSQLColumnAlias($columnName);
|
||||||
$sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias;
|
$sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias;
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
|
||||||
|
|
||||||
if ( ! $hidden) {
|
if ( ! $hidden) {
|
||||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||||
@ -1018,12 +1004,10 @@ class SqlWalker implements TreeWalker
|
|||||||
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
$columnAlias = $this->getSQLColumnAlias('sclr');
|
||||||
$sql .= $this->walkAggregateExpression($expr) . ' AS ' . $columnAlias;
|
$sql .= $this->walkAggregateExpression($expr) . ' AS ' . $columnAlias;
|
||||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||||
|
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
|
||||||
|
|
||||||
if ( ! $hidden) {
|
if ( ! $hidden) {
|
||||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||||
}
|
}
|
||||||
@ -1034,12 +1018,10 @@ class SqlWalker implements TreeWalker
|
|||||||
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
$columnAlias = $this->getSQLColumnAlias('sclr');
|
||||||
$sql .= '(' . $this->walkSubselect($expr) . ') AS '.$columnAlias;
|
$sql .= '(' . $this->walkSubselect($expr) . ') AS '.$columnAlias;
|
||||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||||
|
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
|
||||||
|
|
||||||
if ( ! $hidden) {
|
if ( ! $hidden) {
|
||||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||||
}
|
}
|
||||||
@ -1050,12 +1032,10 @@ class SqlWalker implements TreeWalker
|
|||||||
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
$columnAlias = $this->getSQLColumnAlias('sclr');
|
||||||
$sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias;
|
$sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias;
|
||||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||||
|
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
|
||||||
|
|
||||||
if ( ! $hidden) {
|
if ( ! $hidden) {
|
||||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||||
}
|
}
|
||||||
@ -1072,8 +1052,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
$columnAlias = $this->getSQLColumnAlias('sclr');
|
||||||
|
|
||||||
if ($expr instanceof AST\Literal) {
|
if ($expr instanceof AST\Literal) {
|
||||||
$sql .= $this->walkLiteral($expr) . ' AS ' .$columnAlias;
|
$sql .= $this->walkLiteral($expr) . ' AS ' .$columnAlias;
|
||||||
} else {
|
} else {
|
||||||
@ -1082,8 +1061,6 @@ class SqlWalker implements TreeWalker
|
|||||||
|
|
||||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||||
|
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
|
||||||
|
|
||||||
if ( ! $hidden) {
|
if ( ! $hidden) {
|
||||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||||
}
|
}
|
||||||
@ -1099,14 +1076,11 @@ class SqlWalker implements TreeWalker
|
|||||||
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
$resultAlias = $selectExpression->fieldIdentificationVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
$columnAlias = $this->getSQLColumnAlias('sclr');
|
||||||
|
|
||||||
$sql .= $this->walkCaseExpression($expr) . ' AS ' . $columnAlias;
|
$sql .= $this->walkCaseExpression($expr) . ' AS ' . $columnAlias;
|
||||||
|
|
||||||
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||||
|
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
|
||||||
|
|
||||||
if ( ! $hidden) {
|
if ( ! $hidden) {
|
||||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||||
}
|
}
|
||||||
@ -1146,8 +1120,6 @@ class SqlWalker implements TreeWalker
|
|||||||
$sql .= $sqlTableAlias . '.' . $class->getQuotedColumnName($fieldName, $this->_platform)
|
$sql .= $sqlTableAlias . '.' . $class->getQuotedColumnName($fieldName, $this->_platform)
|
||||||
. ' AS ' . $columnAlias;
|
. ' AS ' . $columnAlias;
|
||||||
|
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
|
||||||
|
|
||||||
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name);
|
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1171,7 +1143,6 @@ class SqlWalker implements TreeWalker
|
|||||||
$sql .= $sqlTableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform)
|
$sql .= $sqlTableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform)
|
||||||
. ' AS ' . $columnAlias;
|
. ' AS ' . $columnAlias;
|
||||||
|
|
||||||
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
|
|
||||||
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName);
|
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1185,7 +1156,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$columnAlias = $this->getSQLColumnAlias($srcColumn);
|
$columnAlias = $this->getSQLColumnAlias($srcColumn);
|
||||||
$sql .= $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
|
$sql .= $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
|
||||||
|
|
||||||
$this->_rsm->addMetaResult($dqlAlias, $this->_platform->getSQLResultCasing($columnAlias), $srcColumn);
|
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1292,83 +1263,77 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function walkSimpleSelectExpression($simpleSelectExpression)
|
public function walkSimpleSelectExpression($simpleSelectExpression)
|
||||||
{
|
{
|
||||||
$sql = '';
|
|
||||||
$expr = $simpleSelectExpression->expression;
|
$expr = $simpleSelectExpression->expression;
|
||||||
|
$sql = ' ';
|
||||||
|
|
||||||
if ($expr instanceof AST\PathExpression) {
|
switch (true) {
|
||||||
$sql .= $this->walkPathExpression($expr);
|
case ($expr instanceof AST\PathExpression):
|
||||||
} else if ($expr instanceof AST\AggregateExpression) {
|
$sql .= $this->walkPathExpression($expr);
|
||||||
if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
|
break;
|
||||||
$alias = $this->_scalarResultCounter++;
|
|
||||||
} else {
|
|
||||||
$alias = $simpleSelectExpression->fieldIdentificationVariable;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= $this->walkAggregateExpression($expr) . ' AS dctrn__' . $alias;
|
case ($expr instanceof AST\AggregateExpression):
|
||||||
} else if ($expr instanceof AST\Subselect) {
|
$alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
|
||||||
if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
|
|
||||||
$alias = $this->_scalarResultCounter++;
|
|
||||||
} else {
|
|
||||||
$alias = $simpleSelectExpression->fieldIdentificationVariable;
|
|
||||||
}
|
|
||||||
|
|
||||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
$sql .= $this->walkAggregateExpression($expr) . ' AS dctrn__' . $alias;
|
||||||
$sql .= '(' . $this->walkSubselect($expr) . ') AS ' . $columnAlias;
|
break;
|
||||||
$this->_scalarResultAliasMap[$alias] = $columnAlias;
|
|
||||||
} else if ($expr instanceof AST\Functions\FunctionNode) {
|
|
||||||
if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
|
|
||||||
$alias = $this->_scalarResultCounter++;
|
|
||||||
} else {
|
|
||||||
$alias = $simpleSelectExpression->fieldIdentificationVariable;
|
|
||||||
}
|
|
||||||
|
|
||||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
case ($expr instanceof AST\Subselect):
|
||||||
$sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias;
|
$alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
|
||||||
$this->_scalarResultAliasMap[$alias] = $columnAlias;
|
|
||||||
} else if (
|
|
||||||
$expr instanceof AST\SimpleArithmeticExpression ||
|
|
||||||
$expr instanceof AST\ArithmeticTerm ||
|
|
||||||
$expr instanceof AST\ArithmeticFactor ||
|
|
||||||
$expr instanceof AST\ArithmeticPrimary
|
|
||||||
) {
|
|
||||||
if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
|
|
||||||
$alias = $this->_scalarResultCounter++;
|
|
||||||
} else {
|
|
||||||
$alias = $simpleSelectExpression->fieldIdentificationVariable;
|
|
||||||
}
|
|
||||||
|
|
||||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
||||||
$sql .= $this->walkSimpleArithmeticExpression($expr) . ' AS ' . $columnAlias;
|
$this->_scalarResultAliasMap[$alias] = $columnAlias;
|
||||||
$this->_scalarResultAliasMap[$alias] = $columnAlias;
|
|
||||||
} else if (
|
|
||||||
$expr instanceof AST\NullIfExpression ||
|
|
||||||
$expr instanceof AST\CoalesceExpression ||
|
|
||||||
$expr instanceof AST\GeneralCaseExpression ||
|
|
||||||
$expr instanceof AST\SimpleCaseExpression
|
|
||||||
) {
|
|
||||||
if ( ! $simpleSelectExpression->fieldIdentificationVariable) {
|
|
||||||
$alias = $this->_scalarResultCounter++;
|
|
||||||
} else {
|
|
||||||
$alias = $simpleSelectExpression->fieldIdentificationVariable;
|
|
||||||
}
|
|
||||||
|
|
||||||
$columnAlias = 'sclr' . $this->_aliasCounter++;
|
$sql .= '(' . $this->walkSubselect($expr) . ') AS ' . $columnAlias;
|
||||||
$sql .= $this->walkCaseExpression($expr) . ' AS ' . $columnAlias;
|
break;
|
||||||
|
|
||||||
$this->_scalarResultAliasMap[$alias] = $columnAlias;
|
case ($expr instanceof AST\Functions\FunctionNode):
|
||||||
} else {
|
$alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
|
||||||
// IdentificationVariable
|
|
||||||
$class = $this->_queryComponents[$expr]['metadata'];
|
|
||||||
$tableAlias = $this->getSQLTableAlias($class->getTableName(), $expr);
|
|
||||||
$first = true;
|
|
||||||
|
|
||||||
foreach ($class->identifier as $identifier) {
|
$columnAlias = $this->getSQLColumnAlias('sclr');
|
||||||
if ($first) $first = false; else $sql .= ', ';
|
$this->_scalarResultAliasMap[$alias] = $columnAlias;
|
||||||
$sql .= $tableAlias . '.' . $class->getQuotedColumnName($identifier, $this->_platform);
|
|
||||||
}
|
$sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ($expr instanceof AST\SimpleArithmeticExpression):
|
||||||
|
case ($expr instanceof AST\ArithmeticTerm):
|
||||||
|
case ($expr instanceof AST\ArithmeticFactor):
|
||||||
|
case ($expr instanceof AST\ArithmeticPrimary):
|
||||||
|
case ($expr instanceof AST\Literal):
|
||||||
|
$alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
|
||||||
|
|
||||||
|
$columnAlias = $this->getSQLColumnAlias('sclr');
|
||||||
|
$this->_scalarResultAliasMap[$alias] = $columnAlias;
|
||||||
|
|
||||||
|
$sql .= $this->walkSimpleArithmeticExpression($expr) . ' AS ' . $columnAlias;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ($expr instanceof AST\NullIfExpression):
|
||||||
|
case ($expr instanceof AST\CoalesceExpression):
|
||||||
|
case ($expr instanceof AST\GeneralCaseExpression):
|
||||||
|
case ($expr instanceof AST\SimpleCaseExpression):
|
||||||
|
$alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
|
||||||
|
|
||||||
|
$columnAlias = $this->getSQLColumnAlias('sclr');
|
||||||
|
$this->_scalarResultAliasMap[$alias] = $columnAlias;
|
||||||
|
|
||||||
|
$sql .= $this->walkCaseExpression($expr) . ' AS ' . $columnAlias;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: // IdentificationVariable
|
||||||
|
$class = $this->_queryComponents[$expr]['metadata'];
|
||||||
|
$tableAlias = $this->getSQLTableAlias($class->getTableName(), $expr);
|
||||||
|
$sqlParts = array();
|
||||||
|
|
||||||
|
foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
|
||||||
|
$sqlParts[] = $tableAlias . '.' . $columnName;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= implode(', ', $sqlParts);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ' ' . $sql;
|
return $sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1391,25 +1356,24 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function walkGroupByClause($groupByClause)
|
public function walkGroupByClause($groupByClause)
|
||||||
{
|
{
|
||||||
$sql = '';
|
$sqlParts = array();
|
||||||
|
|
||||||
foreach ($groupByClause->groupByItems AS $groupByItem) {
|
foreach ($groupByClause->groupByItems AS $groupByItem) {
|
||||||
if (is_string($groupByItem)) {
|
if ( ! is_string($groupByItem)) {
|
||||||
foreach ($this->_queryComponents[$groupByItem]['metadata']->identifier AS $idField) {
|
$sqlParts[] = $this->walkGroupByItem($groupByItem);
|
||||||
if ($sql != '') {
|
|
||||||
$sql .= ', ';
|
continue;
|
||||||
}
|
}
|
||||||
$groupByItem = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $idField);
|
|
||||||
$groupByItem->type = AST\PathExpression::TYPE_STATE_FIELD;
|
foreach ($this->_queryComponents[$groupByItem]['metadata']->identifier AS $idField) {
|
||||||
$sql .= $this->walkGroupByItem($groupByItem);
|
$groupByItem = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $idField);
|
||||||
}
|
$groupByItem->type = AST\PathExpression::TYPE_STATE_FIELD;
|
||||||
} else {
|
|
||||||
if ($sql != '') {
|
$sqlParts[] = $this->walkGroupByItem($groupByItem);
|
||||||
$sql .= ', ';
|
|
||||||
}
|
|
||||||
$sql .= $this->walkGroupByItem($groupByItem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ' GROUP BY ' . $sql;
|
|
||||||
|
return ' GROUP BY ' . implode(', ', $sqlParts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1431,12 +1395,11 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function walkDeleteClause(AST\DeleteClause $deleteClause)
|
public function walkDeleteClause(AST\DeleteClause $deleteClause)
|
||||||
{
|
{
|
||||||
$sql = 'DELETE FROM ';
|
$class = $this->_em->getClassMetadata($deleteClause->abstractSchemaName);
|
||||||
$class = $this->_em->getClassMetadata($deleteClause->abstractSchemaName);
|
$tableName = $class->getTableName();
|
||||||
$sql .= $class->getQuotedTableName($this->_platform);
|
$sql = 'DELETE FROM ' . $class->getQuotedTableName($this->_platform);
|
||||||
|
|
||||||
$this->setSQLTableAlias($class->getTableName(), $class->getTableName(), $deleteClause->aliasIdentificationVariable);
|
|
||||||
|
|
||||||
|
$this->setSQLTableAlias($tableName, $tableName, $deleteClause->aliasIdentificationVariable);
|
||||||
$this->_rootAliases[] = $deleteClause->aliasIdentificationVariable;
|
$this->_rootAliases[] = $deleteClause->aliasIdentificationVariable;
|
||||||
|
|
||||||
return $sql;
|
return $sql;
|
||||||
@ -1450,17 +1413,14 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function walkUpdateClause($updateClause)
|
public function walkUpdateClause($updateClause)
|
||||||
{
|
{
|
||||||
$sql = 'UPDATE ';
|
$class = $this->_em->getClassMetadata($updateClause->abstractSchemaName);
|
||||||
$class = $this->_em->getClassMetadata($updateClause->abstractSchemaName);
|
$tableName = $class->getTableName();
|
||||||
$sql .= $class->getQuotedTableName($this->_platform);
|
$sql = 'UPDATE ' . $class->getQuotedTableName($this->_platform);
|
||||||
|
|
||||||
$this->setSQLTableAlias($class->getTableName(), $class->getTableName(), $updateClause->aliasIdentificationVariable);
|
|
||||||
|
|
||||||
|
$this->setSQLTableAlias($tableName, $tableName, $updateClause->aliasIdentificationVariable);
|
||||||
$this->_rootAliases[] = $updateClause->aliasIdentificationVariable;
|
$this->_rootAliases[] = $updateClause->aliasIdentificationVariable;
|
||||||
|
|
||||||
$sql .= ' SET ' . implode(
|
$sql .= ' SET ' . implode(', ', array_map(array($this, 'walkUpdateItem'), $updateClause->updateItems));
|
||||||
', ', array_map(array($this, 'walkUpdateItem'), $updateClause->updateItems)
|
|
||||||
);
|
|
||||||
|
|
||||||
return $sql;
|
return $sql;
|
||||||
}
|
}
|
||||||
@ -1476,16 +1436,21 @@ class SqlWalker implements TreeWalker
|
|||||||
$useTableAliasesBefore = $this->_useSqlTableAliases;
|
$useTableAliasesBefore = $this->_useSqlTableAliases;
|
||||||
$this->_useSqlTableAliases = false;
|
$this->_useSqlTableAliases = false;
|
||||||
|
|
||||||
$sql = $this->walkPathExpression($updateItem->pathExpression) . ' = ';
|
$sql = $this->walkPathExpression($updateItem->pathExpression) . ' = ';
|
||||||
|
|
||||||
$newValue = $updateItem->newValue;
|
$newValue = $updateItem->newValue;
|
||||||
|
|
||||||
if ($newValue === null) {
|
switch (true) {
|
||||||
$sql .= 'NULL';
|
case ($newValue instanceof AST\Node):
|
||||||
} else if ($newValue instanceof AST\Node) {
|
$sql .= $newValue->dispatch($this);
|
||||||
$sql .= $newValue->dispatch($this);
|
break;
|
||||||
} else {
|
|
||||||
$sql .= $this->_conn->quote($newValue);
|
case ($newValue === null):
|
||||||
|
$sql .= 'NULL';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$sql .= $this->_conn->quote($newValue);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_useSqlTableAliases = $useTableAliasesBefore;
|
$this->_useSqlTableAliases = $useTableAliasesBefore;
|
||||||
@ -1502,12 +1467,14 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function walkWhereClause($whereClause)
|
public function walkWhereClause($whereClause)
|
||||||
{
|
{
|
||||||
$condSql = null !== $whereClause ? $this->walkConditionalExpression($whereClause->conditionalExpression) : '';
|
$condSql = null !== $whereClause ? $this->walkConditionalExpression($whereClause->conditionalExpression) : '';
|
||||||
$discrSql = $this->_generateDiscriminatorColumnConditionSql($this->_rootAliases);
|
$discrSql = $this->_generateDiscriminatorColumnConditionSql($this->_rootAliases);
|
||||||
|
|
||||||
if ($condSql) {
|
if ($condSql) {
|
||||||
return ' WHERE ' . (( ! $discrSql) ? $condSql : '(' . $condSql . ') AND ' . $discrSql);
|
return ' WHERE ' . (( ! $discrSql) ? $condSql : '(' . $condSql . ') AND ' . $discrSql);
|
||||||
} else if ($discrSql) {
|
}
|
||||||
|
|
||||||
|
if ($discrSql) {
|
||||||
return ' WHERE ' . $discrSql;
|
return ' WHERE ' . $discrSql;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1524,11 +1491,11 @@ class SqlWalker implements TreeWalker
|
|||||||
{
|
{
|
||||||
// Phase 2 AST optimization: Skip processment of ConditionalExpression
|
// Phase 2 AST optimization: Skip processment of ConditionalExpression
|
||||||
// if only one ConditionalTerm is defined
|
// if only one ConditionalTerm is defined
|
||||||
return ( ! ($condExpr instanceof AST\ConditionalExpression))
|
if ( ! ($condExpr instanceof AST\ConditionalExpression)) {
|
||||||
? $this->walkConditionalTerm($condExpr)
|
return $this->walkConditionalTerm($condExpr);
|
||||||
: implode(
|
}
|
||||||
' OR ', array_map(array($this, 'walkConditionalTerm'), $condExpr->conditionalTerms)
|
|
||||||
);
|
return implode(' OR ', array_map(array($this, 'walkConditionalTerm'), $condExpr->conditionalTerms));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1541,11 +1508,11 @@ class SqlWalker implements TreeWalker
|
|||||||
{
|
{
|
||||||
// Phase 2 AST optimization: Skip processment of ConditionalTerm
|
// Phase 2 AST optimization: Skip processment of ConditionalTerm
|
||||||
// if only one ConditionalFactor is defined
|
// if only one ConditionalFactor is defined
|
||||||
return ( ! ($condTerm instanceof AST\ConditionalTerm))
|
if ( ! ($condTerm instanceof AST\ConditionalTerm)) {
|
||||||
? $this->walkConditionalFactor($condTerm)
|
return $this->walkConditionalFactor($condTerm);
|
||||||
: implode(
|
}
|
||||||
' AND ', array_map(array($this, 'walkConditionalFactor'), $condTerm->conditionalFactors)
|
|
||||||
);
|
return implode(' AND ', array_map(array($this, 'walkConditionalFactor'), $condTerm->conditionalFactors));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1573,7 +1540,9 @@ class SqlWalker implements TreeWalker
|
|||||||
{
|
{
|
||||||
if ($primary->isSimpleConditionalExpression()) {
|
if ($primary->isSimpleConditionalExpression()) {
|
||||||
return $primary->simpleConditionalExpression->dispatch($this);
|
return $primary->simpleConditionalExpression->dispatch($this);
|
||||||
} else if ($primary->isConditionalExpression()) {
|
}
|
||||||
|
|
||||||
|
if ($primary->isConditionalExpression()) {
|
||||||
$condExpr = $primary->conditionalExpression;
|
$condExpr = $primary->conditionalExpression;
|
||||||
|
|
||||||
return '(' . $this->walkConditionalExpression($condExpr) . ')';
|
return '(' . $this->walkConditionalExpression($condExpr) . ')';
|
||||||
@ -1644,12 +1613,11 @@ class SqlWalker implements TreeWalker
|
|||||||
$sql .= ' AND ';
|
$sql .= ' AND ';
|
||||||
$first = true;
|
$first = true;
|
||||||
|
|
||||||
foreach ($targetClass->identifier as $idField) {
|
foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) {
|
||||||
if ($first) $first = false; else $sql .= ' AND ';
|
if ($first) $first = false; else $sql .= ' AND ';
|
||||||
|
|
||||||
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
|
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
|
||||||
$sql .= $targetTableAlias . '.'
|
$sql .= $targetTableAlias . '.' . $targetColumnName . ' = ?';
|
||||||
. $targetClass->getQuotedColumnName($idField, $this->_platform) . ' = ?';
|
|
||||||
}
|
}
|
||||||
} else { // many-to-many
|
} else { // many-to-many
|
||||||
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
|
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
|
||||||
@ -1694,12 +1662,11 @@ class SqlWalker implements TreeWalker
|
|||||||
$sql .= ' AND ';
|
$sql .= ' AND ';
|
||||||
$first = true;
|
$first = true;
|
||||||
|
|
||||||
foreach ($targetClass->identifier as $idField) {
|
foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) {
|
||||||
if ($first) $first = false; else $sql .= ' AND ';
|
if ($first) $first = false; else $sql .= ' AND ';
|
||||||
|
|
||||||
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
|
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
|
||||||
$sql .= $targetTableAlias . '.'
|
$sql .= $targetTableAlias . '.' . $targetColumnName . ' = ?';
|
||||||
. $targetClass->getQuotedColumnName($idField, $this->_platform) . ' = ?';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1755,11 +1722,9 @@ class SqlWalker implements TreeWalker
|
|||||||
$sql = $this->walkPathExpression($inExpr->pathExpression)
|
$sql = $this->walkPathExpression($inExpr->pathExpression)
|
||||||
. ($inExpr->not ? ' NOT' : '') . ' IN (';
|
. ($inExpr->not ? ' NOT' : '') . ' IN (';
|
||||||
|
|
||||||
if ($inExpr->subselect) {
|
$sql .= ($inExpr->subselect)
|
||||||
$sql .= $this->walkSubselect($inExpr->subselect);
|
? $this->walkSubselect($inExpr->subselect)
|
||||||
} else {
|
: implode(', ', array_map(array($this, 'walkInParameter'), $inExpr->literals));
|
||||||
$sql .= implode(', ', array_map(array($this, 'walkInParameter'), $inExpr->literals));
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= ')';
|
$sql .= ')';
|
||||||
|
|
||||||
@ -1834,9 +1799,9 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function walkInParameter($inParam)
|
public function walkInParameter($inParam)
|
||||||
{
|
{
|
||||||
return $inParam instanceof AST\InputParameter ?
|
return $inParam instanceof AST\InputParameter
|
||||||
$this->walkInputParameter($inParam) :
|
? $this->walkInputParameter($inParam)
|
||||||
$this->walkLiteral($inParam);
|
: $this->walkLiteral($inParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1929,23 +1894,19 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function walkComparisonExpression($compExpr)
|
public function walkComparisonExpression($compExpr)
|
||||||
{
|
{
|
||||||
$sql = '';
|
$leftExpr = $compExpr->leftExpression;
|
||||||
$leftExpr = $compExpr->leftExpression;
|
|
||||||
$rightExpr = $compExpr->rightExpression;
|
$rightExpr = $compExpr->rightExpression;
|
||||||
|
$sql = '';
|
||||||
|
|
||||||
if ($leftExpr instanceof AST\Node) {
|
$sql .= ($leftExpr instanceof AST\Node)
|
||||||
$sql .= $leftExpr->dispatch($this);
|
? $leftExpr->dispatch($this)
|
||||||
} else {
|
: (is_numeric($leftExpr) ? $leftExpr : $this->_conn->quote($leftExpr));
|
||||||
$sql .= is_numeric($leftExpr) ? $leftExpr : $this->_conn->quote($leftExpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= ' ' . $compExpr->operator . ' ';
|
$sql .= ' ' . $compExpr->operator . ' ';
|
||||||
|
|
||||||
if ($rightExpr instanceof AST\Node) {
|
$sql .= ($rightExpr instanceof AST\Node)
|
||||||
$sql .= $rightExpr->dispatch($this);
|
? $rightExpr->dispatch($this)
|
||||||
} else {
|
: (is_numeric($rightExpr) ? $rightExpr : $this->_conn->quote($rightExpr));
|
||||||
$sql .= is_numeric($rightExpr) ? $rightExpr : $this->_conn->quote($rightExpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sql;
|
return $sql;
|
||||||
}
|
}
|
||||||
@ -1984,11 +1945,11 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function walkSimpleArithmeticExpression($simpleArithmeticExpr)
|
public function walkSimpleArithmeticExpression($simpleArithmeticExpr)
|
||||||
{
|
{
|
||||||
return ( ! ($simpleArithmeticExpr instanceof AST\SimpleArithmeticExpression))
|
if ( ! ($simpleArithmeticExpr instanceof AST\SimpleArithmeticExpression)) {
|
||||||
? $this->walkArithmeticTerm($simpleArithmeticExpr)
|
return $this->walkArithmeticTerm($simpleArithmeticExpr);
|
||||||
: implode(
|
}
|
||||||
' ', array_map(array($this, 'walkArithmeticTerm'), $simpleArithmeticExpr->arithmeticTerms)
|
|
||||||
);
|
return implode(' ', array_map(array($this, 'walkArithmeticTerm'), $simpleArithmeticExpr->arithmeticTerms));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2000,22 +1961,18 @@ class SqlWalker implements TreeWalker
|
|||||||
public function walkArithmeticTerm($term)
|
public function walkArithmeticTerm($term)
|
||||||
{
|
{
|
||||||
if (is_string($term)) {
|
if (is_string($term)) {
|
||||||
if (isset($this->_queryComponents[$term])) {
|
return (isset($this->_queryComponents[$term]))
|
||||||
$columnName = $this->_queryComponents[$term]['token']['value'];
|
? $this->_scalarResultAliasMap[$this->_queryComponents[$term]['token']['value']]
|
||||||
|
: $term;
|
||||||
return $this->_scalarResultAliasMap[$columnName];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $term;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase 2 AST optimization: Skip processment of ArithmeticTerm
|
// Phase 2 AST optimization: Skip processment of ArithmeticTerm
|
||||||
// if only one ArithmeticFactor is defined
|
// if only one ArithmeticFactor is defined
|
||||||
return ( ! ($term instanceof AST\ArithmeticTerm))
|
if ( ! ($term instanceof AST\ArithmeticTerm)) {
|
||||||
? $this->walkArithmeticFactor($term)
|
return $this->walkArithmeticFactor($term);
|
||||||
: implode(
|
}
|
||||||
' ', array_map(array($this, 'walkArithmeticFactor'), $term->arithmeticFactors)
|
|
||||||
);
|
return implode(' ', array_map(array($this, 'walkArithmeticFactor'), $term->arithmeticFactors));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2032,10 +1989,13 @@ class SqlWalker implements TreeWalker
|
|||||||
|
|
||||||
// Phase 2 AST optimization: Skip processment of ArithmeticFactor
|
// Phase 2 AST optimization: Skip processment of ArithmeticFactor
|
||||||
// if only one ArithmeticPrimary is defined
|
// if only one ArithmeticPrimary is defined
|
||||||
return ( ! ($factor instanceof AST\ArithmeticFactor))
|
if ( ! ($factor instanceof AST\ArithmeticFactor)) {
|
||||||
? $this->walkArithmeticPrimary($factor)
|
return $this->walkArithmeticPrimary($factor);
|
||||||
: ($factor->isNegativeSigned() ? '-' : ($factor->isPositiveSigned() ? '+' : ''))
|
}
|
||||||
. $this->walkArithmeticPrimary($factor->arithmeticPrimary);
|
|
||||||
|
$sign = $factor->isNegativeSigned() ? '-' : ($factor->isPositiveSigned() ? '+' : '');
|
||||||
|
|
||||||
|
return $sign . $this->walkArithmeticPrimary($factor->arithmeticPrimary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2048,7 +2008,9 @@ class SqlWalker implements TreeWalker
|
|||||||
{
|
{
|
||||||
if ($primary instanceof AST\SimpleArithmeticExpression) {
|
if ($primary instanceof AST\SimpleArithmeticExpression) {
|
||||||
return '(' . $this->walkSimpleArithmeticExpression($primary) . ')';
|
return '(' . $this->walkSimpleArithmeticExpression($primary) . ')';
|
||||||
} else if ($primary instanceof AST\Node) {
|
}
|
||||||
|
|
||||||
|
if ($primary instanceof AST\Node) {
|
||||||
return $primary->dispatch($this);
|
return $primary->dispatch($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,9 @@ class SchemaTool
|
|||||||
/**
|
/**
|
||||||
* Creates the database schema for the given array of ClassMetadata instances.
|
* Creates the database schema for the given array of ClassMetadata instances.
|
||||||
*
|
*
|
||||||
|
* @throws ToolsException
|
||||||
* @param array $classes
|
* @param array $classes
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function createSchema(array $classes)
|
public function createSchema(array $classes)
|
||||||
{
|
{
|
||||||
@ -75,7 +77,11 @@ class SchemaTool
|
|||||||
$conn = $this->_em->getConnection();
|
$conn = $this->_em->getConnection();
|
||||||
|
|
||||||
foreach ($createSchemaSql as $sql) {
|
foreach ($createSchemaSql as $sql) {
|
||||||
$conn->executeQuery($sql);
|
try {
|
||||||
|
$conn->executeQuery($sql);
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
throw ToolsException::schemaToolFailure($sql, $e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
* There are several checks that can't be done at runtime or are too expensive, which can be verified
|
||||||
* with this command. For example:
|
* with this command. For example:
|
||||||
@ -69,150 +69,7 @@ class SchemaValidator
|
|||||||
$classes = $cmf->getAllMetadata();
|
$classes = $cmf->getAllMetadata();
|
||||||
|
|
||||||
foreach ($classes AS $class) {
|
foreach ($classes AS $class) {
|
||||||
$ce = array();
|
if ($ce = $this->validateClass($class)) {
|
||||||
/* @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) {
|
|
||||||
$errors[$class->name] = $ce;
|
$errors[$class->name] = $ce;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,6 +77,165 @@ class SchemaValidator
|
|||||||
return $errors;
|
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.
|
* Check if the Database Schema is in sync with the current metadata state.
|
||||||
*
|
*
|
||||||
|
@ -1,11 +1,38 @@
|
|||||||
<?php
|
<?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;
|
namespace Doctrine\ORM\Tools;
|
||||||
|
|
||||||
use Doctrine\ORM\ORMException;
|
use Doctrine\ORM\ORMException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tools related Exceptions
|
||||||
|
*
|
||||||
|
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||||
|
*/
|
||||||
class ToolsException extends ORMException
|
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)
|
public static function couldNotMapDoctrine1Type($type)
|
||||||
{
|
{
|
||||||
return new self("Could not map doctrine 1 type '$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)
|
public function computeChangeSet(ClassMetadata $class, $entity)
|
||||||
{
|
{
|
||||||
if ( ! $class->isInheritanceTypeNone()) {
|
|
||||||
$class = $this->em->getClassMetadata(get_class($entity));
|
|
||||||
}
|
|
||||||
|
|
||||||
$oid = spl_object_hash($entity);
|
$oid = spl_object_hash($entity);
|
||||||
|
|
||||||
if (isset($this->readOnlyObjects[$oid])) {
|
if (isset($this->readOnlyObjects[$oid])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! $class->isInheritanceTypeNone()) {
|
||||||
|
$class = $this->em->getClassMetadata(get_class($entity));
|
||||||
|
}
|
||||||
|
|
||||||
$actualData = array();
|
$actualData = array();
|
||||||
|
|
||||||
foreach ($class->reflFields as $name => $refProp) {
|
foreach ($class->reflFields as $name => $refProp) {
|
||||||
$value = $refProp->getValue($entity);
|
$value = $refProp->getValue($entity);
|
||||||
|
|
||||||
if (isset($class->associationMappings[$name])
|
if (isset($class->associationMappings[$name])
|
||||||
&& ($class->associationMappings[$name]['type'] & ClassMetadata::TO_MANY)
|
&& ($class->associationMappings[$name]['type'] & ClassMetadata::TO_MANY)
|
||||||
&& $value !== null
|
&& $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.
|
// Loading the entity right here, if its in the eager loading map get rid of it there.
|
||||||
unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
|
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.
|
// Properly initialize any unfetched associations, if partial objects are not allowed.
|
||||||
if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
|
if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
|
||||||
foreach ($class->associationMappings as $field => $assoc) {
|
foreach ($class->associationMappings as $field => $assoc) {
|
||||||
|
@ -9,6 +9,7 @@ class DDC117Article
|
|||||||
{
|
{
|
||||||
/** @Id @Column(type="integer", name="article_id") @GeneratedValue */
|
/** @Id @Column(type="integer", name="article_id") @GeneratedValue */
|
||||||
private $id;
|
private $id;
|
||||||
|
|
||||||
/** @Column */
|
/** @Column */
|
||||||
private $title;
|
private $title;
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class LegacyUser
|
|||||||
*/
|
*/
|
||||||
public $_username;
|
public $_username;
|
||||||
/**
|
/**
|
||||||
* @Column(type="string", length=255)
|
* @Column(type="string", length=255, name="name")
|
||||||
*/
|
*/
|
||||||
public $_name;
|
public $_name;
|
||||||
/**
|
/**
|
||||||
|
@ -23,12 +23,12 @@ class LegacyUserReference
|
|||||||
private $_target;
|
private $_target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @column(type="string")
|
* @column(type="string", name="description")
|
||||||
*/
|
*/
|
||||||
private $_description;
|
private $_description;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @column(type="datetime")
|
* @column(type="datetime", name="created")
|
||||||
*/
|
*/
|
||||||
private $_created;
|
private $_created;
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
/*
|
/*
|
||||||
* $Id$
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
* 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
|
* @link http://www.doctrine-project.org
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
class CustomTreeWalkersTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
class CustomTreeWalkersTest extends \Doctrine\Tests\OrmTestCase
|
||||||
{
|
{
|
||||||
protected function setUp() {
|
private $_em;
|
||||||
$this->useModelSet('cms');
|
|
||||||
parent::setUp();
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->_em = $this->_getTestEntityManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed)
|
public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed)
|
||||||
|
@ -20,7 +20,9 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
|
|
||||||
public function tearDown()
|
public function tearDown()
|
||||||
{
|
{
|
||||||
$this->_em->getConfiguration()->setEntityNamespaces(array());
|
if ($this->_em) {
|
||||||
|
$this->_em->getConfiguration()->setEntityNamespaces(array());
|
||||||
|
}
|
||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,6 +304,49 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
$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()
|
private function loadFixture()
|
||||||
{
|
{
|
||||||
$user1 = new \Doctrine\Tests\Models\CMS\CmsUser();
|
$user1 = new \Doctrine\Tests\Models\CMS\CmsUser();
|
||||||
|
@ -27,14 +27,14 @@ class ReadOnlyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->_em->flush();
|
$this->_em->flush();
|
||||||
|
|
||||||
$readOnly->name = "Test2";
|
$readOnly->name = "Test2";
|
||||||
$readOnly->number = 4321;
|
$readOnly->numericValue = 4321;
|
||||||
|
|
||||||
$this->_em->flush();
|
$this->_em->flush();
|
||||||
$this->_em->clear();
|
$this->_em->clear();
|
||||||
|
|
||||||
$dbReadOnly = $this->_em->find('Doctrine\Tests\ORM\Functional\ReadOnlyEntity', $readOnly->id);
|
$dbReadOnly = $this->_em->find('Doctrine\Tests\ORM\Functional\ReadOnlyEntity', $readOnly->id);
|
||||||
$this->assertEquals("Test1", $dbReadOnly->name);
|
$this->assertEquals("Test1", $dbReadOnly->name);
|
||||||
$this->assertEquals(1234, $dbReadOnly->number);
|
$this->assertEquals(1234, $dbReadOnly->numericValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,11 +51,11 @@ class ReadOnlyEntity
|
|||||||
/** @column(type="string") */
|
/** @column(type="string") */
|
||||||
public $name;
|
public $name;
|
||||||
/** @Column(type="integer") */
|
/** @Column(type="integer") */
|
||||||
public $number;
|
public $numericValue;
|
||||||
|
|
||||||
public function __construct($name, $number)
|
public function __construct($name, $number)
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->number = $number;
|
$this->numericValue = $number;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -90,10 +90,10 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
public function testUseResultCache()
|
public function testUseResultCache()
|
||||||
{
|
{
|
||||||
$cache = new \Doctrine\Common\Cache\ArrayCache();
|
$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 = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
|
||||||
$query->useResultCache(true);
|
$query->useResultCache(true);
|
||||||
|
$query->setResultCacheDriver($cache);
|
||||||
$query->setResultCacheId('testing_result_cache_id');
|
$query->setResultCacheId('testing_result_cache_id');
|
||||||
$users = $query->getResult();
|
$users = $query->getResult();
|
||||||
|
|
||||||
@ -108,11 +108,11 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
public function testUseResultCacheParams()
|
public function testUseResultCacheParams()
|
||||||
{
|
{
|
||||||
$cache = new \Doctrine\Common\Cache\ArrayCache();
|
$cache = new \Doctrine\Common\Cache\ArrayCache();
|
||||||
$this->_em->getConfiguration()->setResultCacheImpl($cache);
|
|
||||||
|
|
||||||
$sqlCount = count($this->_sqlLoggerStack->queries);
|
$sqlCount = count($this->_sqlLoggerStack->queries);
|
||||||
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux WHERE ux.id = ?1');
|
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux WHERE ux.id = ?1');
|
||||||
$query->setParameter(1, 1);
|
$query->setParameter(1, 1);
|
||||||
|
$query->setResultCacheDriver($cache);
|
||||||
$query->useResultCache(true);
|
$query->useResultCache(true);
|
||||||
$query->getResult();
|
$query->getResult();
|
||||||
|
|
||||||
@ -149,10 +149,10 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param <type> $query
|
* @param string $query
|
||||||
* @depends testNativeQueryResultCaching
|
* @depends testNativeQueryResultCaching
|
||||||
*/
|
*/
|
||||||
public function testResultCacheDependsOnQueryHints($query)
|
public function testResultCacheNotDependsOnQueryHints($query)
|
||||||
{
|
{
|
||||||
$cache = $query->getResultCacheDriver();
|
$cache = $query->getResultCacheDriver();
|
||||||
$cacheCount = $this->getCacheSize($cache);
|
$cacheCount = $this->getCacheSize($cache);
|
||||||
@ -160,7 +160,7 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$query->setHint('foo', 'bar');
|
$query->setHint('foo', 'bar');
|
||||||
$query->getResult();
|
$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
|
* @param <type> $query
|
||||||
* @depends testNativeQueryResultCaching
|
* @depends testNativeQueryResultCaching
|
||||||
*/
|
*/
|
||||||
public function testResultCacheDependsOnHydrationMode($query)
|
public function testResultCacheNotDependsOnHydrationMode($query)
|
||||||
{
|
{
|
||||||
$cache = $query->getResultCacheDriver();
|
$cache = $query->getResultCacheDriver();
|
||||||
$cacheCount = $this->getCacheSize($cache);
|
$cacheCount = $this->getCacheSize($cache);
|
||||||
@ -190,7 +190,7 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->assertNotEquals(\Doctrine\ORM\Query::HYDRATE_ARRAY, $query->getHydrationMode());
|
$this->assertNotEquals(\Doctrine\ORM\Query::HYDRATE_ARRAY, $query->getHydrationMode());
|
||||||
$query->getArrayResult();
|
$query->getArrayResult();
|
||||||
|
|
||||||
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
|
$this->assertEquals($cacheCount, $this->getCacheSize($cache));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,11 +44,10 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
->setParameter('author', $user)
|
->setParameter('author', $user)
|
||||||
->getResult();
|
->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)
|
$farticle = $this->_em->createQuery($dql)
|
||||||
->setParameter('author', $user)
|
->setParameter('author', $user)
|
||||||
->setParameter('topic', 'This is John Galt speaking!')
|
->setParameter('topic', 'This is John Galt speaking!')
|
||||||
->setParameter('text', 'Yadda Yadda!')
|
|
||||||
->getSingleResult();
|
->getSingleResult();
|
||||||
|
|
||||||
$this->assertSame($article, $farticle);
|
$this->assertSame($article, $farticle);
|
||||||
@ -70,12 +69,11 @@ class DDC1040Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->_em->persist($article);
|
$this->_em->persist($article);
|
||||||
$this->_em->flush();
|
$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)
|
$farticle = $this->_em->createQuery($dql)
|
||||||
->setParameter(1, 'This is John Galt speaking!')
|
->setParameter(1, 'This is John Galt speaking!')
|
||||||
->setParameter(2, $user)
|
->setParameter(2, $user)
|
||||||
->setParameter(3, $user)
|
->setParameter(3, $user)
|
||||||
->setParameter(4, 'Yadda Yadda!')
|
|
||||||
->getSingleResult();
|
->getSingleResult();
|
||||||
|
|
||||||
$this->assertSame($article, $farticle);
|
$this->assertSame($article, $farticle);
|
||||||
|
@ -106,7 +106,7 @@ class DDC1209_3
|
|||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @Id
|
* @Id
|
||||||
* @Column(type="datetime")
|
* @Column(type="datetime", name="somedate")
|
||||||
*/
|
*/
|
||||||
private $date;
|
private $date;
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ class DDC1225Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
->setParameter(1, 0);
|
->setParameter(1, 0);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SELECT t0_.test_entity2_id AS test_entity2_id0 FROM te1 t0_ WHERE t0_.test_entity2_id = ?',
|
strtolower('SELECT t0_.test_entity2_id AS test_entity2_id0 FROM te1 t0_ WHERE t0_.test_entity2_id = ?'),
|
||||||
$qb->getQuery()->getSQL()
|
strtolower($qb->getQuery()->getSQL())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class DDC1228Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228User'),
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228User'),
|
||||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228Profile'),
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1228Profile'),
|
||||||
));
|
));
|
||||||
} catch(\PDOException $e) {
|
} catch(\Exception $e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,10 +90,10 @@ class DDC1228User
|
|||||||
public $id;
|
public $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @column(type="string")
|
* @Column(type="string")
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $name = '';
|
public $name = 'Bar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @OneToOne(targetEntity="DDC1228Profile")
|
* @OneToOne(targetEntity="DDC1228Profile")
|
||||||
|
@ -19,7 +19,7 @@ class DDC1238Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->_schemaTool->createSchema(array(
|
$this->_schemaTool->createSchema(array(
|
||||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1238User'),
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\\DDC1238User'),
|
||||||
));
|
));
|
||||||
} catch(\PDOException $e) {
|
} catch(\Exception $e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,17 @@ use DateTime;
|
|||||||
require_once __DIR__ . '/../../../TestInit.php';
|
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()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
try {
|
try {
|
||||||
$this->_schemaTool->createSchema(array(
|
$this->_schemaTool->createSchema(array(
|
||||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1135User'),
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1335User'),
|
||||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1135Phone'),
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1335Phone'),
|
||||||
));
|
));
|
||||||
$this->loadFixture();
|
$this->loadFixture();
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
@ -27,7 +27,7 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
|
|
||||||
public function testDql()
|
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);
|
$query = $this->_em->createQuery($dql);
|
||||||
$result = $query->getResult();
|
$result = $query->getResult();
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->assertArrayHasKey(2, $result);
|
$this->assertArrayHasKey(2, $result);
|
||||||
$this->assertArrayHasKey(3, $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);
|
$query = $this->_em->createQuery($dql);
|
||||||
$result = $query->getResult();
|
$result = $query->getResult();
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
public function testTicket()
|
public function testTicket()
|
||||||
{
|
{
|
||||||
$builder = $this->_em->createQueryBuilder();
|
$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();
|
$dql = $builder->getQuery()->getDQL();
|
||||||
$result = $builder->getQuery()->getResult();
|
$result = $builder->getQuery()->getResult();
|
||||||
@ -74,13 +74,13 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->assertArrayHasKey(1, $result);
|
$this->assertArrayHasKey(1, $result);
|
||||||
$this->assertArrayHasKey(2, $result);
|
$this->assertArrayHasKey(2, $result);
|
||||||
$this->assertArrayHasKey(3, $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()
|
public function testIndexByUnique()
|
||||||
{
|
{
|
||||||
$builder = $this->_em->createQueryBuilder();
|
$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();
|
$dql = $builder->getQuery()->getDQL();
|
||||||
$result = $builder->getQuery()->getResult();
|
$result = $builder->getQuery()->getResult();
|
||||||
@ -89,14 +89,14 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->assertArrayHasKey('foo@foo.com', $result);
|
$this->assertArrayHasKey('foo@foo.com', $result);
|
||||||
$this->assertArrayHasKey('bar@bar.com', $result);
|
$this->assertArrayHasKey('bar@bar.com', $result);
|
||||||
$this->assertArrayHasKey('foobar@foobar.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()
|
public function testIndexWithJoin()
|
||||||
{
|
{
|
||||||
$builder = $this->_em->createQueryBuilder();
|
$builder = $this->_em->createQueryBuilder();
|
||||||
$builder->select('u','p')
|
$builder->select('u','p')
|
||||||
->from(__NAMESPACE__ . '\DDC1135User', 'u', 'u.email')
|
->from(__NAMESPACE__ . '\DDC1335User', 'u', 'u.email')
|
||||||
->join('u.phones', 'p', null, null, 'p.id');
|
->join('u.phones', 'p', null, null, 'p.id');
|
||||||
|
|
||||||
$dql = $builder->getQuery()->getDQL();
|
$dql = $builder->getQuery()->getDQL();
|
||||||
@ -123,7 +123,7 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->assertArrayHasKey(8, $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->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()
|
private function loadFixture()
|
||||||
@ -132,9 +132,9 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$p2 = array('22 xxxx-xxxx','22 yyyy-yyyy','22 zzzz-zzzz');
|
$p2 = array('22 xxxx-xxxx','22 yyyy-yyyy','22 zzzz-zzzz');
|
||||||
$p3 = array('33 xxxx-xxxx','33 yyyy-yyyy','33 zzzz-zzzz');
|
$p3 = array('33 xxxx-xxxx','33 yyyy-yyyy','33 zzzz-zzzz');
|
||||||
|
|
||||||
$u1 = new DDC1135User("foo@foo.com", "Foo",$p1);
|
$u1 = new DDC1335User("foo@foo.com", "Foo",$p1);
|
||||||
$u2 = new DDC1135User("bar@bar.com", "Bar",$p2);
|
$u2 = new DDC1335User("bar@bar.com", "Bar",$p2);
|
||||||
$u3 = new DDC1135User("foobar@foobar.com", "Foo Bar",$p3);
|
$u3 = new DDC1335User("foobar@foobar.com", "Foo Bar",$p3);
|
||||||
|
|
||||||
$this->_em->persist($u1);
|
$this->_em->persist($u1);
|
||||||
$this->_em->persist($u2);
|
$this->_em->persist($u2);
|
||||||
@ -148,7 +148,7 @@ class DDC1135Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
/**
|
/**
|
||||||
* @Entity
|
* @Entity
|
||||||
*/
|
*/
|
||||||
class DDC1135User
|
class DDC1335User
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @Id @Column(type="integer")
|
* @Id @Column(type="integer")
|
||||||
@ -167,7 +167,7 @@ class DDC1135User
|
|||||||
public $name;
|
public $name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @OneToMany(targetEntity="DDC1135Phone", mappedBy="user", cascade={"persist", "remove"})
|
* @OneToMany(targetEntity="DDC1335Phone", mappedBy="user", cascade={"persist", "remove"})
|
||||||
*/
|
*/
|
||||||
public $phones;
|
public $phones;
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ class DDC1135User
|
|||||||
$this->phones = new \Doctrine\Common\Collections\ArrayCollection();
|
$this->phones = new \Doctrine\Common\Collections\ArrayCollection();
|
||||||
|
|
||||||
foreach ($numbers as $number) {
|
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
|
* @Entity
|
||||||
*/
|
*/
|
||||||
class DDC1135Phone
|
class DDC1335Phone
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @Id
|
* @Id
|
||||||
* @Column(name="id", type="integer")
|
* @Column(name="id", type="integer")
|
||||||
* @GeneratedValue(strategy="AUTO")
|
* @GeneratedValue
|
||||||
*/
|
*/
|
||||||
public $id;
|
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)
|
* @JoinColumn(name="user_id", referencedColumnName="id", nullable = false)
|
||||||
*/
|
*/
|
||||||
public $user;
|
public $user;
|
||||||
@ -209,6 +209,6 @@ class DDC1135Phone
|
|||||||
public function __construct($user, $number)
|
public function __construct($user, $number)
|
||||||
{
|
{
|
||||||
$this->user = $user;
|
$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();
|
parent::setUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-331
|
||||||
|
*/
|
||||||
public function testSelectFieldOnRootEntity()
|
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');
|
$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()
|
public function testIssue()
|
||||||
{
|
{
|
||||||
$q = $this->_em->createQuery("select b from ".__NAMESPACE__."\\DDC448SubTable b where b.connectedClassId = ?1");
|
$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()
|
public function testIssue()
|
||||||
{
|
{
|
||||||
$q = $this->_em->createQuery("select u, c.data from ".__NAMESPACE__."\\DDC493Distributor u JOIN u.contact c");
|
$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()
|
public function testIssue()
|
||||||
{
|
{
|
||||||
$q = $this->_em->createQuery("select u from ".__NAMESPACE__."\\DDC513OfferItem u left join u.price p");
|
$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();
|
$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');
|
$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())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,10 +34,10 @@ class DDC949Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$true = $this->_em->getRepository('Doctrine\Tests\Models\Generic\BooleanModel')->findOneBy(array('booleanField' => true));
|
$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));
|
$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->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.");
|
$this->assertFalse($false->booleanField, "False Boolean Model should be false.");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -604,7 +604,24 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
. ' WHERE EXISTS ('
|
. ' WHERE EXISTS ('
|
||||||
. 'SELECT c1_.id FROM cms_employees c1_ WHERE c1_.id = c0_.spouse_id'
|
. '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'
|
||||||
|
. ')'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,12 +746,12 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
|
|
||||||
$this->assertSqlGeneration(
|
$this->assertSqlGeneration(
|
||||||
"SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = true",
|
"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(
|
$this->assertSqlGeneration(
|
||||||
"SELECT b FROM Doctrine\Tests\Models\Generic\BooleanModel b WHERE b.booleanField = false",
|
"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);
|
$this->_em->getConnection()->setDatabasePlatform($oldPlat);
|
||||||
@ -877,7 +894,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
|
|
||||||
$this->assertSqlGeneration(
|
$this->assertSqlGeneration(
|
||||||
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'",
|
"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",
|
"FROM cms_users c0_ WHERE c0_.username = 'gblanco' FOR UPDATE",
|
||||||
array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::PESSIMISTIC_READ)
|
array(Query::HINT_LOCK_MODE => \Doctrine\DBAL\LockMode::PESSIMISTIC_READ)
|
||||||
);
|
);
|
||||||
@ -1251,6 +1268,39 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
|
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)"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1281,3 +1331,15 @@ class MyAbsFunction extends \Doctrine\ORM\Query\AST\Functions\FunctionNode
|
|||||||
$parser->match(\Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS);
|
$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();
|
$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