Merge remote-tracking branch 'upstream/master' into DDC-551
Conflicts: lib/Doctrine/ORM/Persisters/ManyToManyPersister.php lib/Doctrine/ORM/Persisters/OneToManyPersister.php
This commit is contained in:
commit
04635ad4ff
@ -1,6 +1,6 @@
|
|||||||
# ResultCache implementation rewritten
|
# ResultCache implementation rewritten
|
||||||
|
|
||||||
The result cache is completly rewritten and now works on the database result level, not inside the ORM AbstractQuery
|
The result cache is completely 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
|
anymore. This means that for result cached queries the hydration will now always be performed again, regardless of
|
||||||
the hydration mode. Affected areas are:
|
the hydration mode. Affected areas are:
|
||||||
|
|
||||||
@ -12,20 +12,24 @@ The API is backwards compatible however most of the getter methods on the `Abstr
|
|||||||
deprecated in favor of calling AbstractQuery#getQueryCacheProfile(). This method returns a `Doctrine\DBAL\Cache\QueryCacheProfile`
|
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.
|
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
|
||||||
haven't been in the identity map before. This means objects of this kind never lead to changes
|
haven't been in the identity map before. This means objects of this kind never lead to changes
|
||||||
in the UnitOfWork.
|
in the UnitOfWork.
|
||||||
|
|
||||||
|
|
||||||
# Fields omitted in a partial DQL query or a native query are never updated
|
# Fields omitted in a partial DQL query or a native query are never updated
|
||||||
|
|
||||||
Fields of an entity that are not returned from a partial DQL Query or native SQL query
|
Fields of an entity that are not returned from a partial DQL Query or native SQL query
|
||||||
will never be updated through an UPDATE statement.
|
will never be updated through an UPDATE statement.
|
||||||
|
|
||||||
|
|
||||||
# Removed support for onUpdate in @JoinColumn
|
# Removed support for onUpdate in @JoinColumn
|
||||||
|
|
||||||
The onUpdate foreign key handling makes absolutly no sense in an ORM. Additionally Oracle doesn't even support it. Support for it is removed.
|
The onUpdate foreign key handling makes absolutely no sense in an ORM. Additionally Oracle doesn't even support it. Support for it is removed.
|
||||||
|
|
||||||
|
|
||||||
# Changes in Annotation Handling
|
# Changes in Annotation Handling
|
||||||
|
|
||||||
@ -42,3 +46,31 @@ from 2.0 have to configure the annotation driver if they don't use `Configuratio
|
|||||||
$driver = new AnnotationDriver($reader, (array)$paths);
|
$driver = new AnnotationDriver($reader, (array)$paths);
|
||||||
|
|
||||||
$config->setMetadataDriverImpl($driver);
|
$config->setMetadataDriverImpl($driver);
|
||||||
|
|
||||||
|
|
||||||
|
# Scalar mappings can now be ommitted from DQL result
|
||||||
|
|
||||||
|
You are now allowed to mark scalar SELECT expressions as HIDDEN an they are not hydrated anymore.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
SELECT u, SUM(a.id) AS HIDDEN numArticles FROM User u LEFT JOIN u.Articles a ORDER BY numArticles DESC HAVING numArticles > 10
|
||||||
|
|
||||||
|
Your result will be a collection of Users, and not an array with key 0 as User object instance and "numArticles" as the number of articles per user
|
||||||
|
|
||||||
|
|
||||||
|
# Map entities as scalars in DQL result
|
||||||
|
|
||||||
|
When hydrating to array or even a mixed result in object hydrator, previously you had the 0 index holding you entity instance.
|
||||||
|
You are now allowed to alias this, providing more flexibility for you code.
|
||||||
|
Example:
|
||||||
|
|
||||||
|
SELECT u AS user FROM User u
|
||||||
|
|
||||||
|
Will now return a collection of arrays with index "user" pointing to the User object instance.
|
||||||
|
|
||||||
|
|
||||||
|
# Performance optimizations
|
||||||
|
|
||||||
|
Thousands of lines were completely reviewed and optimized for best performance.
|
||||||
|
Removed redundancy and improved code readability made now internal Doctrine code easier to understand.
|
||||||
|
Also, Doctrine 2.2 now is around 10-15% faster than 2.1.
|
@ -163,7 +163,11 @@ abstract class AbstractQuery
|
|||||||
*/
|
*/
|
||||||
public function getParameter($key)
|
public function getParameter($key)
|
||||||
{
|
{
|
||||||
return isset($this->_params[$key]) ? $this->_params[$key] : null;
|
if (isset($this->_params[$key])) {
|
||||||
|
return $this->_params[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,7 +178,11 @@ abstract class AbstractQuery
|
|||||||
*/
|
*/
|
||||||
public function getParameterType($key)
|
public function getParameterType($key)
|
||||||
{
|
{
|
||||||
return isset($this->_paramTypes[$key]) ? $this->_paramTypes[$key] : null;
|
if (isset($this->_paramTypes[$key])) {
|
||||||
|
return $this->_paramTypes[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,12 +228,9 @@ abstract class AbstractQuery
|
|||||||
public function setParameters(array $params, array $types = array())
|
public function setParameters(array $params, array $types = array())
|
||||||
{
|
{
|
||||||
foreach ($params as $key => $value) {
|
foreach ($params as $key => $value) {
|
||||||
if (isset($types[$key])) {
|
$this->setParameter($key, $value, isset($types[$key]) ? $types[$key] : null);
|
||||||
$this->setParameter($key, $value, $types[$key]);
|
|
||||||
} else {
|
|
||||||
$this->setParameter($key, $value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +243,7 @@ abstract class AbstractQuery
|
|||||||
public function setResultSetMapping(Query\ResultSetMapping $rsm)
|
public function setResultSetMapping(Query\ResultSetMapping $rsm)
|
||||||
{
|
{
|
||||||
$this->_resultSetMapping = $rsm;
|
$this->_resultSetMapping = $rsm;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,11 +258,11 @@ 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();
|
||||||
}
|
}
|
||||||
if ($this->_queryCacheProfile) {
|
|
||||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver);
|
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||||
} else {
|
? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
|
||||||
$this->_queryCacheProfile = new QueryCacheProfile(0, null, $resultCacheDriver);
|
: new QueryCacheProfile(0, null, $resultCacheDriver);
|
||||||
}
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,9 +276,9 @@ abstract class AbstractQuery
|
|||||||
{
|
{
|
||||||
if ($this->_queryCacheProfile && $this->_queryCacheProfile->getResultCacheDriver()) {
|
if ($this->_queryCacheProfile && $this->_queryCacheProfile->getResultCacheDriver()) {
|
||||||
return $this->_queryCacheProfile->getResultCacheDriver();
|
return $this->_queryCacheProfile->getResultCacheDriver();
|
||||||
} else {
|
|
||||||
return $this->_em->getConfiguration()->getResultCacheImpl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->_em->getConfiguration()->getResultCacheImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -289,9 +295,12 @@ abstract class AbstractQuery
|
|||||||
if ($bool) {
|
if ($bool) {
|
||||||
$this->setResultCacheLifetime($lifetime);
|
$this->setResultCacheLifetime($lifetime);
|
||||||
$this->setResultCacheId($resultCacheId);
|
$this->setResultCacheId($resultCacheId);
|
||||||
} else {
|
|
||||||
$this->_queryCacheProfile = null;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->_queryCacheProfile = null;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,16 +312,12 @@ abstract class AbstractQuery
|
|||||||
*/
|
*/
|
||||||
public function setResultCacheLifetime($lifetime)
|
public function setResultCacheLifetime($lifetime)
|
||||||
{
|
{
|
||||||
if ($lifetime === null) {
|
$lifetime = ($lifetime !== null) ? (int) $lifetime : 0;
|
||||||
$lifetime = 0;
|
|
||||||
} else {
|
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||||
$lifetime = (int)$lifetime;
|
? $this->_queryCacheProfile->setLifetime($lifetime)
|
||||||
}
|
: new QueryCacheProfile($lifetime);
|
||||||
if ($this->_queryCacheProfile) {
|
|
||||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setLifetime($lifetime);
|
|
||||||
} else {
|
|
||||||
$this->_queryCacheProfile = new QueryCacheProfile($lifetime);
|
|
||||||
}
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,6 +341,7 @@ abstract class AbstractQuery
|
|||||||
public function expireResultCache($expire = true)
|
public function expireResultCache($expire = true)
|
||||||
{
|
{
|
||||||
$this->_expireResultCache = $expire;
|
$this->_expireResultCache = $expire;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,6 +380,7 @@ abstract class AbstractQuery
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->_hints['fetchMode'][$class][$assocName] = $fetchMode;
|
$this->_hints['fetchMode'][$class][$assocName] = $fetchMode;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,6 +394,7 @@ abstract class AbstractQuery
|
|||||||
public function setHydrationMode($hydrationMode)
|
public function setHydrationMode($hydrationMode)
|
||||||
{
|
{
|
||||||
$this->_hydrationMode = $hydrationMode;
|
$this->_hydrationMode = $hydrationMode;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,14 +459,15 @@ abstract class AbstractQuery
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($result)) {
|
if ( ! is_array($result)) {
|
||||||
if (count($result) > 1) {
|
return $result;
|
||||||
throw new NonUniqueResultException;
|
|
||||||
}
|
|
||||||
return array_shift($result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
if (count($result) > 1) {
|
||||||
|
throw new NonUniqueResultException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_shift($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -482,14 +491,15 @@ abstract class AbstractQuery
|
|||||||
throw new NoResultException;
|
throw new NoResultException;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($result)) {
|
if ( ! is_array($result)) {
|
||||||
if (count($result) > 1) {
|
return $result;
|
||||||
throw new NonUniqueResultException;
|
|
||||||
}
|
|
||||||
return array_shift($result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
if (count($result) > 1) {
|
||||||
|
throw new NonUniqueResultException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_shift($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -515,6 +525,7 @@ abstract class AbstractQuery
|
|||||||
public function setHint($name, $value)
|
public function setHint($name, $value)
|
||||||
{
|
{
|
||||||
$this->_hints[$name] = $value;
|
$this->_hints[$name] = $value;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,8 +599,8 @@ abstract class AbstractQuery
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
|
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
|
||||||
$stmt, $this->_resultSetMapping, $this->_hints
|
$stmt, $this->_resultSetMapping, $this->_hints
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -602,11 +613,10 @@ abstract class AbstractQuery
|
|||||||
*/
|
*/
|
||||||
public function setResultCacheId($id)
|
public function setResultCacheId($id)
|
||||||
{
|
{
|
||||||
if ($this->_queryCacheProfile) {
|
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setCacheKey($id);
|
? $this->_queryCacheProfile->setCacheKey($id)
|
||||||
} else {
|
: new QueryCacheProfile(0, $id);
|
||||||
$this->_queryCacheProfile = new QueryCacheProfile(0, $id);
|
|
||||||
}
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,10 +138,12 @@ class EntityManager implements ObjectManager
|
|||||||
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
|
$this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
|
||||||
|
|
||||||
$this->unitOfWork = new UnitOfWork($this);
|
$this->unitOfWork = new UnitOfWork($this);
|
||||||
$this->proxyFactory = new ProxyFactory($this,
|
$this->proxyFactory = new ProxyFactory(
|
||||||
$config->getProxyDir(),
|
$this,
|
||||||
$config->getProxyNamespace(),
|
$config->getProxyDir(),
|
||||||
$config->getAutoGenerateProxyClasses());
|
$config->getProxyNamespace(),
|
||||||
|
$config->getAutoGenerateProxyClasses()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,6 +185,7 @@ class EntityManager implements ObjectManager
|
|||||||
if ($this->expressionBuilder === null) {
|
if ($this->expressionBuilder === null) {
|
||||||
$this->expressionBuilder = new Query\Expr;
|
$this->expressionBuilder = new Query\Expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->expressionBuilder;
|
return $this->expressionBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,9 +278,11 @@ class EntityManager implements ObjectManager
|
|||||||
public function createQuery($dql = "")
|
public function createQuery($dql = "")
|
||||||
{
|
{
|
||||||
$query = new Query($this);
|
$query = new Query($this);
|
||||||
|
|
||||||
if ( ! empty($dql)) {
|
if ( ! empty($dql)) {
|
||||||
$query->setDql($dql);
|
$query->setDql($dql);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,6 +309,7 @@ class EntityManager implements ObjectManager
|
|||||||
$query = new NativeQuery($this);
|
$query = new NativeQuery($this);
|
||||||
$query->setSql($sql);
|
$query->setSql($sql);
|
||||||
$query->setResultSetMapping($rsm);
|
$query->setResultSetMapping($rsm);
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,6 +322,7 @@ class EntityManager implements ObjectManager
|
|||||||
public function createNamedNativeQuery($name)
|
public function createNamedNativeQuery($name)
|
||||||
{
|
{
|
||||||
list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
|
list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
|
||||||
|
|
||||||
return $this->createNativeQuery($sql, $rsm);
|
return $this->createNativeQuery($sql, $rsm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,6 +351,7 @@ class EntityManager implements ObjectManager
|
|||||||
public function flush($entity = null)
|
public function flush($entity = null)
|
||||||
{
|
{
|
||||||
$this->errorIfClosed();
|
$this->errorIfClosed();
|
||||||
|
|
||||||
$this->unitOfWork->commit($entity);
|
$this->unitOfWork->commit($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,27 +376,39 @@ class EntityManager implements ObjectManager
|
|||||||
* without actually loading it, if the entity is not yet loaded.
|
* without actually loading it, if the entity is not yet loaded.
|
||||||
*
|
*
|
||||||
* @param string $entityName The name of the entity type.
|
* @param string $entityName The name of the entity type.
|
||||||
* @param mixed $identifier The entity identifier.
|
* @param mixed $id The entity identifier.
|
||||||
* @return object The entity reference.
|
* @return object The entity reference.
|
||||||
*/
|
*/
|
||||||
public function getReference($entityName, $identifier)
|
public function getReference($entityName, $id)
|
||||||
{
|
{
|
||||||
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
|
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
|
||||||
|
if ( ! is_array($id)) {
|
||||||
|
$id = array($class->identifier[0] => $id);
|
||||||
|
}
|
||||||
|
$sortedId = array();
|
||||||
|
foreach ($class->identifier as $identifier) {
|
||||||
|
if (!isset($id[$identifier])) {
|
||||||
|
throw ORMException::missingIdentifierField($class->name, $identifier);
|
||||||
|
}
|
||||||
|
$sortedId[$identifier] = $id[$identifier];
|
||||||
|
}
|
||||||
|
|
||||||
// Check identity map first, if its already in there just return it.
|
// Check identity map first, if its already in there just return it.
|
||||||
if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
|
if ($entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName)) {
|
||||||
return ($entity instanceof $class->name) ? $entity : null;
|
return ($entity instanceof $class->name) ? $entity : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($class->subClasses) {
|
if ($class->subClasses) {
|
||||||
$entity = $this->find($entityName, $identifier);
|
return $this->find($entityName, $sortedId);
|
||||||
} else {
|
|
||||||
if ( ! is_array($identifier)) {
|
|
||||||
$identifier = array($class->identifier[0] => $identifier);
|
|
||||||
}
|
|
||||||
$entity = $this->proxyFactory->getProxy($class->name, $identifier);
|
|
||||||
$this->unitOfWork->registerManaged($entity, $identifier, array());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! is_array($sortedId)) {
|
||||||
|
$sortedId = array($class->identifier[0] => $sortedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
$entity = $this->proxyFactory->getProxy($class->name, $sortedId);
|
||||||
|
$this->unitOfWork->registerManaged($entity, $sortedId, array());
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,6 +439,7 @@ class EntityManager implements ObjectManager
|
|||||||
if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
|
if ($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) {
|
||||||
return ($entity instanceof $class->name) ? $entity : null;
|
return ($entity instanceof $class->name) ? $entity : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! is_array($identifier)) {
|
if ( ! is_array($identifier)) {
|
||||||
$identifier = array($class->identifier[0] => $identifier);
|
$identifier = array($class->identifier[0] => $identifier);
|
||||||
}
|
}
|
||||||
@ -469,7 +490,9 @@ class EntityManager implements ObjectManager
|
|||||||
if ( ! is_object($entity)) {
|
if ( ! is_object($entity)) {
|
||||||
throw new \InvalidArgumentException(gettype($entity));
|
throw new \InvalidArgumentException(gettype($entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->errorIfClosed();
|
$this->errorIfClosed();
|
||||||
|
|
||||||
$this->unitOfWork->persist($entity);
|
$this->unitOfWork->persist($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,7 +509,9 @@ class EntityManager implements ObjectManager
|
|||||||
if ( ! is_object($entity)) {
|
if ( ! is_object($entity)) {
|
||||||
throw new \InvalidArgumentException(gettype($entity));
|
throw new \InvalidArgumentException(gettype($entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->errorIfClosed();
|
$this->errorIfClosed();
|
||||||
|
|
||||||
$this->unitOfWork->remove($entity);
|
$this->unitOfWork->remove($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,7 +526,9 @@ class EntityManager implements ObjectManager
|
|||||||
if ( ! is_object($entity)) {
|
if ( ! is_object($entity)) {
|
||||||
throw new \InvalidArgumentException(gettype($entity));
|
throw new \InvalidArgumentException(gettype($entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->errorIfClosed();
|
$this->errorIfClosed();
|
||||||
|
|
||||||
$this->unitOfWork->refresh($entity);
|
$this->unitOfWork->refresh($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,6 +546,7 @@ class EntityManager implements ObjectManager
|
|||||||
if ( ! is_object($entity)) {
|
if ( ! is_object($entity)) {
|
||||||
throw new \InvalidArgumentException(gettype($entity));
|
throw new \InvalidArgumentException(gettype($entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->unitOfWork->detach($entity);
|
$this->unitOfWork->detach($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,7 +563,9 @@ class EntityManager implements ObjectManager
|
|||||||
if ( ! is_object($entity)) {
|
if ( ! is_object($entity)) {
|
||||||
throw new \InvalidArgumentException(gettype($entity));
|
throw new \InvalidArgumentException(gettype($entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->errorIfClosed();
|
$this->errorIfClosed();
|
||||||
|
|
||||||
return $this->unitOfWork->merge($entity);
|
return $this->unitOfWork->merge($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,20 +605,20 @@ class EntityManager implements ObjectManager
|
|||||||
public function getRepository($entityName)
|
public function getRepository($entityName)
|
||||||
{
|
{
|
||||||
$entityName = ltrim($entityName, '\\');
|
$entityName = ltrim($entityName, '\\');
|
||||||
|
|
||||||
if (isset($this->repositories[$entityName])) {
|
if (isset($this->repositories[$entityName])) {
|
||||||
return $this->repositories[$entityName];
|
return $this->repositories[$entityName];
|
||||||
}
|
}
|
||||||
|
|
||||||
$metadata = $this->getClassMetadata($entityName);
|
$metadata = $this->getClassMetadata($entityName);
|
||||||
$customRepositoryClassName = $metadata->customRepositoryClassName;
|
$repositoryClassName = $metadata->customRepositoryClassName;
|
||||||
|
|
||||||
if ($customRepositoryClassName !== null) {
|
if ($repositoryClassName === null) {
|
||||||
$repository = new $customRepositoryClassName($this, $metadata);
|
$repositoryClassName = $this->config->getDefaultRepositoryClassName();
|
||||||
} else {
|
|
||||||
$repositoryClass = $this->config->getDefaultRepositoryClassName();
|
|
||||||
$repository = new $repositoryClass($this, $metadata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$repository = new $repositoryClassName($this, $metadata);
|
||||||
|
|
||||||
$this->repositories[$entityName] = $repository;
|
$this->repositories[$entityName] = $repository;
|
||||||
|
|
||||||
return $repository;
|
return $repository;
|
||||||
@ -602,9 +632,9 @@ class EntityManager implements ObjectManager
|
|||||||
*/
|
*/
|
||||||
public function contains($entity)
|
public function contains($entity)
|
||||||
{
|
{
|
||||||
return $this->unitOfWork->isScheduledForInsert($entity) ||
|
return $this->unitOfWork->isScheduledForInsert($entity)
|
||||||
$this->unitOfWork->isInIdentityMap($entity) &&
|
|| $this->unitOfWork->isInIdentityMap($entity)
|
||||||
! $this->unitOfWork->isScheduledForDelete($entity);
|
&& ! $this->unitOfWork->isScheduledForDelete($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -687,29 +717,27 @@ class EntityManager implements ObjectManager
|
|||||||
{
|
{
|
||||||
switch ($hydrationMode) {
|
switch ($hydrationMode) {
|
||||||
case Query::HYDRATE_OBJECT:
|
case Query::HYDRATE_OBJECT:
|
||||||
$hydrator = new Internal\Hydration\ObjectHydrator($this);
|
return new Internal\Hydration\ObjectHydrator($this);
|
||||||
break;
|
|
||||||
case Query::HYDRATE_ARRAY:
|
case Query::HYDRATE_ARRAY:
|
||||||
$hydrator = new Internal\Hydration\ArrayHydrator($this);
|
return new Internal\Hydration\ArrayHydrator($this);
|
||||||
break;
|
|
||||||
case Query::HYDRATE_SCALAR:
|
case Query::HYDRATE_SCALAR:
|
||||||
$hydrator = new Internal\Hydration\ScalarHydrator($this);
|
return new Internal\Hydration\ScalarHydrator($this);
|
||||||
break;
|
|
||||||
case Query::HYDRATE_SINGLE_SCALAR:
|
case Query::HYDRATE_SINGLE_SCALAR:
|
||||||
$hydrator = new Internal\Hydration\SingleScalarHydrator($this);
|
return new Internal\Hydration\SingleScalarHydrator($this);
|
||||||
break;
|
|
||||||
case Query::HYDRATE_SIMPLEOBJECT:
|
case Query::HYDRATE_SIMPLEOBJECT:
|
||||||
$hydrator = new Internal\Hydration\SimpleObjectHydrator($this);
|
return new Internal\Hydration\SimpleObjectHydrator($this);
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
if ($class = $this->config->getCustomHydrationMode($hydrationMode)) {
|
if ($class = $this->config->getCustomHydrationMode($hydrationMode)) {
|
||||||
$hydrator = new $class($this);
|
return new $class($this);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
throw ORMException::invalidHydrationMode($hydrationMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $hydrator;
|
throw ORMException::invalidHydrationMode($hydrationMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -745,18 +773,25 @@ class EntityManager implements ObjectManager
|
|||||||
*/
|
*/
|
||||||
public static function create($conn, Configuration $config, EventManager $eventManager = null)
|
public static function create($conn, Configuration $config, EventManager $eventManager = null)
|
||||||
{
|
{
|
||||||
if (!$config->getMetadataDriverImpl()) {
|
if ( ! $config->getMetadataDriverImpl()) {
|
||||||
throw ORMException::missingMappingDriverImpl();
|
throw ORMException::missingMappingDriverImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($conn)) {
|
switch (true) {
|
||||||
$conn = \Doctrine\DBAL\DriverManager::getConnection($conn, $config, ($eventManager ?: new EventManager()));
|
case (is_array($conn)):
|
||||||
} else if ($conn instanceof Connection) {
|
$conn = \Doctrine\DBAL\DriverManager::getConnection(
|
||||||
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
|
$conn, $config, ($eventManager ?: new EventManager())
|
||||||
throw ORMException::mismatchedEventManager();
|
);
|
||||||
}
|
break;
|
||||||
} else {
|
|
||||||
throw new \InvalidArgumentException("Invalid argument: " . $conn);
|
case ($conn instanceof Connection):
|
||||||
|
if ($eventManager !== null && $conn->getEventManager() !== $eventManager) {
|
||||||
|
throw ORMException::mismatchedEventManager();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException("Invalid argument: " . $conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new EntityManager($conn, $config, $conn->getEventManager());
|
return new EntityManager($conn, $config, $conn->getEventManager());
|
||||||
|
@ -107,42 +107,51 @@ class EntityRepository implements ObjectRepository
|
|||||||
*/
|
*/
|
||||||
public function find($id, $lockMode = LockMode::NONE, $lockVersion = null)
|
public function find($id, $lockMode = LockMode::NONE, $lockVersion = null)
|
||||||
{
|
{
|
||||||
|
if ( ! is_array($id)) {
|
||||||
|
$id = array($this->_class->identifier[0] => $id);
|
||||||
|
}
|
||||||
|
$sortedId = array();
|
||||||
|
foreach ($this->_class->identifier as $identifier) {
|
||||||
|
if (!isset($id[$identifier])) {
|
||||||
|
throw ORMException::missingIdentifierField($this->_class->name, $identifier);
|
||||||
|
}
|
||||||
|
$sortedId[$identifier] = $id[$identifier];
|
||||||
|
}
|
||||||
|
|
||||||
// Check identity map first
|
// Check identity map first
|
||||||
if ($entity = $this->_em->getUnitOfWork()->tryGetById($id, $this->_class->rootEntityName)) {
|
if ($entity = $this->_em->getUnitOfWork()->tryGetById($sortedId, $this->_class->rootEntityName)) {
|
||||||
if (!($entity instanceof $this->_class->name)) {
|
if ( ! ($entity instanceof $this->_class->name)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($lockMode != LockMode::NONE) {
|
if ($lockMode !== LockMode::NONE) {
|
||||||
$this->_em->lock($entity, $lockMode, $lockVersion);
|
$this->_em->lock($entity, $lockMode, $lockVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity; // Hit!
|
return $entity; // Hit!
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! is_array($id) || count($id) <= 1) {
|
switch ($lockMode) {
|
||||||
// @todo FIXME: Not correct. Relies on specific order.
|
case LockMode::NONE:
|
||||||
$value = is_array($id) ? array_values($id) : array($id);
|
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId);
|
||||||
$id = array_combine($this->_class->identifier, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($lockMode == LockMode::NONE) {
|
case LockMode::OPTIMISTIC:
|
||||||
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id);
|
if ( ! $this->_class->isVersioned) {
|
||||||
} else if ($lockMode == LockMode::OPTIMISTIC) {
|
throw OptimisticLockException::notVersioned($this->_entityName);
|
||||||
if (!$this->_class->isVersioned) {
|
}
|
||||||
throw OptimisticLockException::notVersioned($this->_entityName);
|
|
||||||
}
|
|
||||||
$entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id);
|
|
||||||
|
|
||||||
$this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion);
|
$entity = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId);
|
||||||
|
|
||||||
return $entity;
|
$this->_em->getUnitOfWork()->lock($entity, $lockMode, $lockVersion);
|
||||||
} else {
|
|
||||||
if (!$this->_em->getConnection()->isTransactionActive()) {
|
|
||||||
throw TransactionRequiredException::transactionRequired();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($id, null, null, array(), $lockMode);
|
return $entity;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if ( ! $this->_em->getConnection()->isTransactionActive()) {
|
||||||
|
throw TransactionRequiredException::transactionRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->load($sortedId, null, null, array(), $lockMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,30 +200,35 @@ class EntityRepository implements ObjectRepository
|
|||||||
*/
|
*/
|
||||||
public function __call($method, $arguments)
|
public function __call($method, $arguments)
|
||||||
{
|
{
|
||||||
if (substr($method, 0, 6) == 'findBy') {
|
switch (true) {
|
||||||
$by = substr($method, 6, strlen($method));
|
case (substr($method, 0, 6) == 'findBy'):
|
||||||
$method = 'findBy';
|
$by = substr($method, 6, strlen($method));
|
||||||
} else if (substr($method, 0, 9) == 'findOneBy') {
|
$method = 'findBy';
|
||||||
$by = substr($method, 9, strlen($method));
|
break;
|
||||||
$method = 'findOneBy';
|
|
||||||
} else {
|
case (substr($method, 0, 9) == 'findOneBy'):
|
||||||
throw new \BadMethodCallException(
|
$by = substr($method, 9, strlen($method));
|
||||||
"Undefined method '$method'. The method name must start with ".
|
$method = 'findOneBy';
|
||||||
"either findBy or findOneBy!"
|
break;
|
||||||
);
|
|
||||||
|
default:
|
||||||
|
throw new \BadMethodCallException(
|
||||||
|
"Undefined method '$method'. The method name must start with ".
|
||||||
|
"either findBy or findOneBy!"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($arguments)) {
|
if (empty($arguments)) {
|
||||||
throw ORMException::findByRequiresParameter($method.$by);
|
throw ORMException::findByRequiresParameter($method . $by);
|
||||||
}
|
}
|
||||||
|
|
||||||
$fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by));
|
$fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by));
|
||||||
|
|
||||||
if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) {
|
if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) {
|
||||||
return $this->$method(array($fieldName => $arguments[0]));
|
return $this->$method(array($fieldName => $arguments[0]));
|
||||||
} else {
|
|
||||||
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,8 +23,9 @@ namespace Doctrine\ORM\Internal;
|
|||||||
* The CommitOrderCalculator is used by the UnitOfWork to sort out the
|
* The CommitOrderCalculator is used by the UnitOfWork to sort out the
|
||||||
* correct order in which changes to entities need to be persisted.
|
* correct order in which changes to entities need to be persisted.
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
*/
|
*/
|
||||||
class CommitOrderCalculator
|
class CommitOrderCalculator
|
||||||
{
|
{
|
||||||
@ -60,10 +61,9 @@ class CommitOrderCalculator
|
|||||||
{
|
{
|
||||||
// Check whether we need to do anything. 0 or 1 node is easy.
|
// Check whether we need to do anything. 0 or 1 node is easy.
|
||||||
$nodeCount = count($this->_classes);
|
$nodeCount = count($this->_classes);
|
||||||
if ($nodeCount == 0) {
|
|
||||||
return array();
|
if ($nodeCount <= 1) {
|
||||||
} else if ($nodeCount == 1) {
|
return ($nodeCount == 1) ? array_values($this->_classes) : array();
|
||||||
return array_values($this->_classes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
|
@ -28,11 +28,6 @@ use PDO, Doctrine\DBAL\Connection, Doctrine\ORM\Mapping\ClassMetadata;
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
||||||
*
|
|
||||||
* @todo General behavior is "wrong" if you define an alias to selected IdentificationVariable.
|
|
||||||
* Example: SELECT u AS user FROM User u
|
|
||||||
* The result should contains an array where each array index is an array: array('user' => [User object])
|
|
||||||
* Problem must be solved somehow by removing the isMixed in ResultSetMapping
|
|
||||||
*/
|
*/
|
||||||
class ArrayHydrator extends AbstractHydrator
|
class ArrayHydrator extends AbstractHydrator
|
||||||
{
|
{
|
||||||
|
@ -23,6 +23,8 @@ use PDO,
|
|||||||
Doctrine\ORM\Mapping\ClassMetadata,
|
Doctrine\ORM\Mapping\ClassMetadata,
|
||||||
Doctrine\ORM\PersistentCollection,
|
Doctrine\ORM\PersistentCollection,
|
||||||
Doctrine\ORM\Query,
|
Doctrine\ORM\Query,
|
||||||
|
Doctrine\ORM\Event\LifecycleEventArgs,
|
||||||
|
Doctrine\ORM\Events,
|
||||||
Doctrine\Common\Collections\ArrayCollection,
|
Doctrine\Common\Collections\ArrayCollection,
|
||||||
Doctrine\Common\Collections\Collection;
|
Doctrine\Common\Collections\Collection;
|
||||||
|
|
||||||
@ -34,11 +36,6 @@ use PDO,
|
|||||||
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
|
||||||
*
|
*
|
||||||
* @internal Highly performance-sensitive code.
|
* @internal Highly performance-sensitive code.
|
||||||
*
|
|
||||||
* @todo General behavior is "wrong" if you define an alias to selected IdentificationVariable.
|
|
||||||
* Example: SELECT u AS user FROM User u
|
|
||||||
* The result should contains an array where each array index is an array: array('user' => [User object])
|
|
||||||
* Problem must be solved somehow by removing the isMixed in ResultSetMapping
|
|
||||||
*/
|
*/
|
||||||
class ObjectHydrator extends AbstractHydrator
|
class ObjectHydrator extends AbstractHydrator
|
||||||
{
|
{
|
||||||
@ -235,7 +232,21 @@ class ObjectHydrator extends AbstractHydrator
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->_hints['fetchAlias'] = $dqlAlias;
|
$this->_hints['fetchAlias'] = $dqlAlias;
|
||||||
return $this->_uow->createEntity($className, $data, $this->_hints);
|
|
||||||
|
$entity = $this->_uow->createEntity($className, $data, $this->_hints);
|
||||||
|
|
||||||
|
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
|
||||||
|
if (isset($this->_ce[$className]->lifecycleCallbacks[Events::postLoad])) {
|
||||||
|
$this->_ce[$className]->invokeLifecycleCallbacks(Events::postLoad, $entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
$evm = $this->_em->getEventManager();
|
||||||
|
|
||||||
|
if ($evm->hasListeners(Events::postLoad)) {
|
||||||
|
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _getEntityFromIdentityMap($className, array $data)
|
private function _getEntityFromIdentityMap($className, array $data)
|
||||||
|
@ -19,10 +19,12 @@
|
|||||||
|
|
||||||
namespace Doctrine\ORM\Internal\Hydration;
|
namespace Doctrine\ORM\Internal\Hydration;
|
||||||
|
|
||||||
use \PDO;
|
use \PDO,
|
||||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
Doctrine\DBAL\Types\Type,
|
||||||
use Doctrine\DBAL\Types\Type;
|
Doctrine\ORM\Mapping\ClassMetadata,
|
||||||
use Doctrine\ORM\Query;
|
Doctrine\ORM\Event\LifecycleEventArgs,
|
||||||
|
Doctrine\ORM\Events,
|
||||||
|
Doctrine\ORM\Query;
|
||||||
|
|
||||||
class SimpleObjectHydrator extends AbstractHydrator
|
class SimpleObjectHydrator extends AbstractHydrator
|
||||||
{
|
{
|
||||||
@ -125,7 +127,21 @@ class SimpleObjectHydrator extends AbstractHydrator
|
|||||||
$this->registerManaged($this->class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
|
$this->registerManaged($this->class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[] = $this->_em->getUnitOfWork()->createEntity($entityName, $data, $this->_hints);
|
$uow = $this->_em->getUnitOfWork();
|
||||||
|
$entity = $uow->createEntity($entityName, $data, $this->_hints);
|
||||||
|
|
||||||
|
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
|
||||||
|
if (isset($this->class->lifecycleCallbacks[Events::postLoad])) {
|
||||||
|
$this->class->invokeLifecycleCallbacks(Events::postLoad, $entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
$evm = $this->_em->getEventManager();
|
||||||
|
|
||||||
|
if ($evm->hasListeners(Events::postLoad)) {
|
||||||
|
$evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em));
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[] = $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
24
lib/Doctrine/ORM/Mapping/Annotation.php
Normal file
24
lib/Doctrine/ORM/Mapping/Annotation.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
interface Annotation
|
||||||
|
{
|
||||||
|
}
|
30
lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php
Normal file
30
lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
*/
|
||||||
|
final class ChangeTrackingPolicy implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $value;
|
||||||
|
}
|
@ -135,20 +135,25 @@ class ClassMetadata extends ClassMetadataInfo
|
|||||||
{
|
{
|
||||||
if ($this->isIdentifierComposite) {
|
if ($this->isIdentifierComposite) {
|
||||||
$id = array();
|
$id = array();
|
||||||
|
|
||||||
foreach ($this->identifier as $idField) {
|
foreach ($this->identifier as $idField) {
|
||||||
$value = $this->reflFields[$idField]->getValue($entity);
|
$value = $this->reflFields[$idField]->getValue($entity);
|
||||||
|
|
||||||
if ($value !== null) {
|
if ($value !== null) {
|
||||||
$id[$idField] = $value;
|
$id[$idField] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $id;
|
return $id;
|
||||||
} else {
|
|
||||||
$value = $this->reflFields[$this->identifier[0]]->getValue($entity);
|
|
||||||
if ($value !== null) {
|
|
||||||
return array($this->identifier[0] => $value);
|
|
||||||
}
|
|
||||||
return array();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$value = $this->reflFields[$this->identifier[0]]->getValue($entity);
|
||||||
|
|
||||||
|
if ($value !== null) {
|
||||||
|
return array($this->identifier[0] => $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -310,21 +315,18 @@ class ClassMetadata extends ClassMetadataInfo
|
|||||||
$this->reflClass = new ReflectionClass($this->name);
|
$this->reflClass = new ReflectionClass($this->name);
|
||||||
|
|
||||||
foreach ($this->fieldMappings as $field => $mapping) {
|
foreach ($this->fieldMappings as $field => $mapping) {
|
||||||
if (isset($mapping['declared'])) {
|
$reflField = isset($mapping['declared'])
|
||||||
$reflField = new ReflectionProperty($mapping['declared'], $field);
|
? new ReflectionProperty($mapping['declared'], $field)
|
||||||
} else {
|
: $this->reflClass->getProperty($field);
|
||||||
$reflField = $this->reflClass->getProperty($field);
|
|
||||||
}
|
|
||||||
$reflField->setAccessible(true);
|
$reflField->setAccessible(true);
|
||||||
$this->reflFields[$field] = $reflField;
|
$this->reflFields[$field] = $reflField;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->associationMappings as $field => $mapping) {
|
foreach ($this->associationMappings as $field => $mapping) {
|
||||||
if (isset($mapping['declared'])) {
|
$reflField = isset($mapping['declared'])
|
||||||
$reflField = new ReflectionProperty($mapping['declared'], $field);
|
? new ReflectionProperty($mapping['declared'], $field)
|
||||||
} else {
|
: $this->reflClass->getProperty($field);
|
||||||
$reflField = $this->reflClass->getProperty($field);
|
|
||||||
}
|
|
||||||
|
|
||||||
$reflField->setAccessible(true);
|
$reflField->setAccessible(true);
|
||||||
$this->reflFields[$field] = $reflField;
|
$this->reflFields[$field] = $reflField;
|
||||||
@ -341,6 +343,7 @@ class ClassMetadata extends ClassMetadataInfo
|
|||||||
if ($this->_prototype === null) {
|
if ($this->_prototype === null) {
|
||||||
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
|
$this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
return clone $this->_prototype;
|
return clone $this->_prototype;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,6 +357,7 @@ class ClassMetadata extends ClassMetadataInfo
|
|||||||
($this->reflClass->getMethod($callback)->getModifiers() & \ReflectionMethod::IS_PUBLIC) == 0) {
|
($this->reflClass->getMethod($callback)->getModifiers() & \ReflectionMethod::IS_PUBLIC) == 0) {
|
||||||
throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callback);
|
throw MappingException::lifecycleCallbackMethodNotFound($this->name, $callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::addLifecycleCallback($callback, $event);
|
return parent::addLifecycleCallback($callback, $event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -521,6 +521,12 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
|
|||||||
$this->initialize();
|
$this->initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for namespace alias
|
||||||
|
if (strpos($class, ':') !== false) {
|
||||||
|
list($namespaceAlias, $simpleClassName) = explode(':', $class);
|
||||||
|
$class = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->driver->isTransient($class);
|
return $this->driver->isTransient($class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
46
lib/Doctrine/ORM/Mapping/Column.php
Normal file
46
lib/Doctrine/ORM/Mapping/Column.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class Column implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
/** @var mixed */
|
||||||
|
public $type = 'string';
|
||||||
|
/** @var integer */
|
||||||
|
public $length;
|
||||||
|
/** @var integer */
|
||||||
|
public $precision = 0; // The precision for a decimal (exact numeric) column (Applies only for decimal column)
|
||||||
|
/** @var integer */
|
||||||
|
public $scale = 0; // The scale for a decimal (exact numeric) column (Applies only for decimal column)
|
||||||
|
/** @var boolean */
|
||||||
|
public $unique = false;
|
||||||
|
/** @var boolean */
|
||||||
|
public $nullable = false;
|
||||||
|
/** @var array */
|
||||||
|
public $options = array();
|
||||||
|
/** @var string */
|
||||||
|
public $columnDefinition;
|
||||||
|
}
|
36
lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php
Normal file
36
lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
*/
|
||||||
|
final class DiscriminatorColumn implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
/** @var string */
|
||||||
|
public $type;
|
||||||
|
/** @var integer */
|
||||||
|
public $length;
|
||||||
|
/** @var mixed */
|
||||||
|
public $fieldName; // field name used in non-object hydration (array/scalar)
|
||||||
|
}
|
30
lib/Doctrine/ORM/Mapping/DiscriminatorMap.php
Normal file
30
lib/Doctrine/ORM/Mapping/DiscriminatorMap.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
*/
|
||||||
|
final class DiscriminatorMap implements Annotation
|
||||||
|
{
|
||||||
|
/** @var array<string> */
|
||||||
|
public $value;
|
||||||
|
}
|
@ -17,379 +17,38 @@
|
|||||||
* <http://www.doctrine-project.org>.
|
* <http://www.doctrine-project.org>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Doctrine\ORM\Mapping;
|
require_once __DIR__.'/../Annotation.php';
|
||||||
|
require_once __DIR__.'/../Entity.php';
|
||||||
interface Annotation {}
|
require_once __DIR__.'/../MappedSuperclass.php';
|
||||||
|
require_once __DIR__.'/../InheritanceType.php';
|
||||||
|
require_once __DIR__.'/../DiscriminatorColumn.php';
|
||||||
/* Annotations */
|
require_once __DIR__.'/../DiscriminatorMap.php';
|
||||||
|
require_once __DIR__.'/../Id.php';
|
||||||
/**
|
require_once __DIR__.'/../GeneratedValue.php';
|
||||||
* @Annotation
|
require_once __DIR__.'/../Version.php';
|
||||||
* @Target("CLASS")
|
require_once __DIR__.'/../JoinColumn.php';
|
||||||
*/
|
require_once __DIR__.'/../JoinColumns.php';
|
||||||
final class Entity implements Annotation {
|
require_once __DIR__.'/../Column.php';
|
||||||
/** @var string */
|
require_once __DIR__.'/../OneToOne.php';
|
||||||
public $repositoryClass;
|
require_once __DIR__.'/../OneToMany.php';
|
||||||
/** @var boolean */
|
require_once __DIR__.'/../ManyToOne.php';
|
||||||
public $readOnly = false;
|
require_once __DIR__.'/../ManyToMany.php';
|
||||||
}
|
require_once __DIR__.'/../ElementCollection.php';
|
||||||
|
require_once __DIR__.'/../Table.php';
|
||||||
/**
|
require_once __DIR__.'/../UniqueConstraint.php';
|
||||||
* @Annotation
|
require_once __DIR__.'/../Index.php';
|
||||||
* @Target("CLASS")
|
require_once __DIR__.'/../JoinTable.php';
|
||||||
*/
|
require_once __DIR__.'/../SequenceGenerator.php';
|
||||||
final class MappedSuperclass implements Annotation {
|
require_once __DIR__.'/../ChangeTrackingPolicy.php';
|
||||||
/** @var string */
|
require_once __DIR__.'/../OrderBy.php';
|
||||||
public $repositoryClass;
|
require_once __DIR__.'/../NamedQueries.php';
|
||||||
}
|
require_once __DIR__.'/../NamedQuery.php';
|
||||||
|
require_once __DIR__.'/../HasLifecycleCallbacks.php';
|
||||||
/**
|
require_once __DIR__.'/../PrePersist.php';
|
||||||
* @Annotation
|
require_once __DIR__.'/../PostPersist.php';
|
||||||
* @Target("CLASS")
|
require_once __DIR__.'/../PreUpdate.php';
|
||||||
*/
|
require_once __DIR__.'/../PostUpdate.php';
|
||||||
final class InheritanceType implements Annotation {
|
require_once __DIR__.'/../PreRemove.php';
|
||||||
/** @var string */
|
require_once __DIR__.'/../PostRemove.php';
|
||||||
public $value;
|
require_once __DIR__.'/../PostLoad.php';
|
||||||
}
|
require_once __DIR__.'/../PreFlush.php';
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("CLASS")
|
|
||||||
*/
|
|
||||||
final class DiscriminatorColumn implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $name;
|
|
||||||
/** @var string */
|
|
||||||
public $type;
|
|
||||||
/** @var integer */
|
|
||||||
public $length;
|
|
||||||
/** @var mixed */
|
|
||||||
public $fieldName; // field name used in non-object hydration (array/scalar)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("CLASS")
|
|
||||||
*/
|
|
||||||
final class DiscriminatorMap implements Annotation {
|
|
||||||
/** @var array<string> */
|
|
||||||
public $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class Id implements Annotation {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class GeneratedValue implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $strategy = 'AUTO';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class Version implements Annotation {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target({"PROPERTY","ANNOTATION"})
|
|
||||||
*/
|
|
||||||
final class JoinColumn implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $name;
|
|
||||||
/** @var string */
|
|
||||||
public $referencedColumnName = 'id';
|
|
||||||
/** @var boolean */
|
|
||||||
public $unique = false;
|
|
||||||
/** @var boolean */
|
|
||||||
public $nullable = true;
|
|
||||||
/** @var mixed */
|
|
||||||
public $onDelete;
|
|
||||||
/** @var string */
|
|
||||||
public $columnDefinition;
|
|
||||||
/** @var string */
|
|
||||||
public $fieldName; // field name used in non-object hydration (array/scalar)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class JoinColumns implements Annotation {
|
|
||||||
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
|
|
||||||
public $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class Column implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $name;
|
|
||||||
/** @var mixed */
|
|
||||||
public $type = 'string';
|
|
||||||
/** @var integer */
|
|
||||||
public $length;
|
|
||||||
/** @var integer */
|
|
||||||
public $precision = 0; // The precision for a decimal (exact numeric) column (Applies only for decimal column)
|
|
||||||
/** @var integer */
|
|
||||||
public $scale = 0; // The scale for a decimal (exact numeric) column (Applies only for decimal column)
|
|
||||||
/** @var boolean */
|
|
||||||
public $unique = false;
|
|
||||||
/** @var boolean */
|
|
||||||
public $nullable = false;
|
|
||||||
/** @var array */
|
|
||||||
public $options = array();
|
|
||||||
/** @var string */
|
|
||||||
public $columnDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class OneToOne implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $targetEntity;
|
|
||||||
/** @var string */
|
|
||||||
public $mappedBy;
|
|
||||||
/** @var string */
|
|
||||||
public $inversedBy;
|
|
||||||
/** @var array<string> */
|
|
||||||
public $cascade;
|
|
||||||
/** @var string */
|
|
||||||
public $fetch = 'LAZY';
|
|
||||||
/** @var boolean */
|
|
||||||
public $orphanRemoval = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class OneToMany implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $mappedBy;
|
|
||||||
/** @var string */
|
|
||||||
public $targetEntity;
|
|
||||||
/** @var array<string> */
|
|
||||||
public $cascade;
|
|
||||||
/** @var string */
|
|
||||||
public $fetch = 'LAZY';
|
|
||||||
/** @var boolean */
|
|
||||||
public $orphanRemoval = false;
|
|
||||||
/** @var string */
|
|
||||||
public $indexBy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class ManyToOne implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $targetEntity;
|
|
||||||
/** @var array<string> */
|
|
||||||
public $cascade;
|
|
||||||
/** @var string */
|
|
||||||
public $fetch = 'LAZY';
|
|
||||||
/** @var string */
|
|
||||||
public $inversedBy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class ManyToMany implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $targetEntity;
|
|
||||||
/** @var string */
|
|
||||||
public $mappedBy;
|
|
||||||
/** @var string */
|
|
||||||
public $inversedBy;
|
|
||||||
/** @var array<string> */
|
|
||||||
public $cascade;
|
|
||||||
/** @var string */
|
|
||||||
public $fetch = 'LAZY';
|
|
||||||
/** @var string */
|
|
||||||
public $indexBy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("ALL")
|
|
||||||
* @todo check available targets
|
|
||||||
*/
|
|
||||||
final class ElementCollection implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $tableName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("CLASS")
|
|
||||||
*/
|
|
||||||
final class Table implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $name;
|
|
||||||
/** @var string */
|
|
||||||
public $schema;
|
|
||||||
/** @var array<Doctrine\ORM\Mapping\Index> */
|
|
||||||
public $indexes;
|
|
||||||
/** @var array<Doctrine\ORM\Mapping\UniqueConstraint> */
|
|
||||||
public $uniqueConstraints;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("ANNOTATION")
|
|
||||||
*/
|
|
||||||
final class UniqueConstraint implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $name;
|
|
||||||
/** @var array<string> */
|
|
||||||
public $columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("ANNOTATION")
|
|
||||||
*/
|
|
||||||
final class Index implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $name;
|
|
||||||
/** @var array<string> */
|
|
||||||
public $columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class JoinTable implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $name;
|
|
||||||
/** @var string */
|
|
||||||
public $schema;
|
|
||||||
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
|
|
||||||
public $joinColumns = array();
|
|
||||||
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
|
|
||||||
public $inverseJoinColumns = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class SequenceGenerator implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $sequenceName;
|
|
||||||
/** @var integer */
|
|
||||||
public $allocationSize = 1;
|
|
||||||
/** @var integer */
|
|
||||||
public $initialValue = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("CLASS")
|
|
||||||
*/
|
|
||||||
final class ChangeTrackingPolicy implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("PROPERTY")
|
|
||||||
*/
|
|
||||||
final class OrderBy implements Annotation {
|
|
||||||
/** @var array<string> */
|
|
||||||
public $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("CLASS")
|
|
||||||
*/
|
|
||||||
final class NamedQueries implements Annotation {
|
|
||||||
/** @var array<Doctrine\ORM\Mapping\NamedQuery> */
|
|
||||||
public $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("ANNOTATION")
|
|
||||||
*/
|
|
||||||
final class NamedQuery implements Annotation {
|
|
||||||
/** @var string */
|
|
||||||
public $name;
|
|
||||||
/** @var string */
|
|
||||||
public $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Annotations for lifecycle callbacks */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("CLASS")
|
|
||||||
*/
|
|
||||||
final class HasLifecycleCallbacks implements Annotation {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("METHOD")
|
|
||||||
*/
|
|
||||||
final class PrePersist implements Annotation {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("METHOD")
|
|
||||||
*/
|
|
||||||
final class PostPersist implements Annotation {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("METHOD")
|
|
||||||
*/
|
|
||||||
final class PreUpdate implements Annotation {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("METHOD")
|
|
||||||
*/
|
|
||||||
final class PostUpdate implements Annotation {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("METHOD")
|
|
||||||
*/
|
|
||||||
final class PreRemove implements Annotation {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("METHOD")
|
|
||||||
*/
|
|
||||||
final class PostRemove implements Annotation {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("METHOD")
|
|
||||||
*/
|
|
||||||
final class PostLoad implements Annotation {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @Target("METHOD")
|
|
||||||
*/
|
|
||||||
final class PreFlush implements Annotation {}
|
|
||||||
|
@ -233,6 +233,10 @@ class XmlDriver extends AbstractFileDriver
|
|||||||
$mapping['columnName'] = (string)$idElement['column'];
|
$mapping['columnName'] = (string)$idElement['column'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($idElement['column-definition'])) {
|
||||||
|
$mapping['columnDefinition'] = (string)$idElement['column-definition'];
|
||||||
|
}
|
||||||
|
|
||||||
$metadata->mapField($mapping);
|
$metadata->mapField($mapping);
|
||||||
|
|
||||||
if (isset($idElement->generator)) {
|
if (isset($idElement->generator)) {
|
||||||
|
@ -182,6 +182,10 @@ class YamlDriver extends AbstractFileDriver
|
|||||||
$mapping['length'] = $idElement['length'];
|
$mapping['length'] = $idElement['length'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($idElement['columnDefinition'])) {
|
||||||
|
$mapping['columnDefinition'] = $idElement['columnDefinition'];
|
||||||
|
}
|
||||||
|
|
||||||
$metadata->mapField($mapping);
|
$metadata->mapField($mapping);
|
||||||
|
|
||||||
if (isset($idElement['generator'])) {
|
if (isset($idElement['generator'])) {
|
||||||
|
31
lib/Doctrine/ORM/Mapping/ElementCollection.php
Normal file
31
lib/Doctrine/ORM/Mapping/ElementCollection.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("ALL")
|
||||||
|
* @todo check available targets
|
||||||
|
*/
|
||||||
|
final class ElementCollection implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $tableName;
|
||||||
|
}
|
32
lib/Doctrine/ORM/Mapping/Entity.php
Normal file
32
lib/Doctrine/ORM/Mapping/Entity.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
*/
|
||||||
|
final class Entity implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $repositoryClass;
|
||||||
|
/** @var boolean */
|
||||||
|
public $readOnly = false;
|
||||||
|
}
|
30
lib/Doctrine/ORM/Mapping/GeneratedValue.php
Normal file
30
lib/Doctrine/ORM/Mapping/GeneratedValue.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class GeneratedValue implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $strategy = 'AUTO';
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php
Normal file
28
lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
*/
|
||||||
|
final class HasLifecycleCallbacks implements Annotation
|
||||||
|
{
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/Id.php
Normal file
28
lib/Doctrine/ORM/Mapping/Id.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class Id implements Annotation
|
||||||
|
{
|
||||||
|
}
|
32
lib/Doctrine/ORM/Mapping/Index.php
Normal file
32
lib/Doctrine/ORM/Mapping/Index.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("ANNOTATION")
|
||||||
|
*/
|
||||||
|
final class Index implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
/** @var array<string> */
|
||||||
|
public $columns;
|
||||||
|
}
|
30
lib/Doctrine/ORM/Mapping/InheritanceType.php
Normal file
30
lib/Doctrine/ORM/Mapping/InheritanceType.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
*/
|
||||||
|
final class InheritanceType implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $value;
|
||||||
|
}
|
42
lib/Doctrine/ORM/Mapping/JoinColumn.php
Normal file
42
lib/Doctrine/ORM/Mapping/JoinColumn.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target({"PROPERTY","ANNOTATION"})
|
||||||
|
*/
|
||||||
|
final class JoinColumn implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
/** @var string */
|
||||||
|
public $referencedColumnName = 'id';
|
||||||
|
/** @var boolean */
|
||||||
|
public $unique = false;
|
||||||
|
/** @var boolean */
|
||||||
|
public $nullable = true;
|
||||||
|
/** @var mixed */
|
||||||
|
public $onDelete;
|
||||||
|
/** @var string */
|
||||||
|
public $columnDefinition;
|
||||||
|
/** @var string */
|
||||||
|
public $fieldName; // field name used in non-object hydration (array/scalar)
|
||||||
|
}
|
30
lib/Doctrine/ORM/Mapping/JoinColumns.php
Normal file
30
lib/Doctrine/ORM/Mapping/JoinColumns.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class JoinColumns implements Annotation
|
||||||
|
{
|
||||||
|
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
|
||||||
|
public $value;
|
||||||
|
}
|
36
lib/Doctrine/ORM/Mapping/JoinTable.php
Normal file
36
lib/Doctrine/ORM/Mapping/JoinTable.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class JoinTable implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
/** @var string */
|
||||||
|
public $schema;
|
||||||
|
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
|
||||||
|
public $joinColumns = array();
|
||||||
|
/** @var array<Doctrine\ORM\Mapping\JoinColumn> */
|
||||||
|
public $inverseJoinColumns = array();
|
||||||
|
}
|
40
lib/Doctrine/ORM/Mapping/ManyToMany.php
Normal file
40
lib/Doctrine/ORM/Mapping/ManyToMany.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class ManyToMany implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $targetEntity;
|
||||||
|
/** @var string */
|
||||||
|
public $mappedBy;
|
||||||
|
/** @var string */
|
||||||
|
public $inversedBy;
|
||||||
|
/** @var array<string> */
|
||||||
|
public $cascade;
|
||||||
|
/** @var string */
|
||||||
|
public $fetch = 'LAZY';
|
||||||
|
/** @var string */
|
||||||
|
public $indexBy;
|
||||||
|
}
|
36
lib/Doctrine/ORM/Mapping/ManyToOne.php
Normal file
36
lib/Doctrine/ORM/Mapping/ManyToOne.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class ManyToOne implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $targetEntity;
|
||||||
|
/** @var array<string> */
|
||||||
|
public $cascade;
|
||||||
|
/** @var string */
|
||||||
|
public $fetch = 'LAZY';
|
||||||
|
/** @var string */
|
||||||
|
public $inversedBy;
|
||||||
|
}
|
30
lib/Doctrine/ORM/Mapping/MappedSuperclass.php
Normal file
30
lib/Doctrine/ORM/Mapping/MappedSuperclass.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
*/
|
||||||
|
final class MappedSuperclass implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $repositoryClass;
|
||||||
|
}
|
30
lib/Doctrine/ORM/Mapping/NamedQueries.php
Normal file
30
lib/Doctrine/ORM/Mapping/NamedQueries.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
*/
|
||||||
|
final class NamedQueries implements Annotation
|
||||||
|
{
|
||||||
|
/** @var array<Doctrine\ORM\Mapping\NamedQuery> */
|
||||||
|
public $value;
|
||||||
|
}
|
32
lib/Doctrine/ORM/Mapping/NamedQuery.php
Normal file
32
lib/Doctrine/ORM/Mapping/NamedQuery.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("ANNOTATION")
|
||||||
|
*/
|
||||||
|
final class NamedQuery implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
/** @var string */
|
||||||
|
public $query;
|
||||||
|
}
|
40
lib/Doctrine/ORM/Mapping/OneToMany.php
Normal file
40
lib/Doctrine/ORM/Mapping/OneToMany.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class OneToMany implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $mappedBy;
|
||||||
|
/** @var string */
|
||||||
|
public $targetEntity;
|
||||||
|
/** @var array<string> */
|
||||||
|
public $cascade;
|
||||||
|
/** @var string */
|
||||||
|
public $fetch = 'LAZY';
|
||||||
|
/** @var boolean */
|
||||||
|
public $orphanRemoval = false;
|
||||||
|
/** @var string */
|
||||||
|
public $indexBy;
|
||||||
|
}
|
40
lib/Doctrine/ORM/Mapping/OneToOne.php
Normal file
40
lib/Doctrine/ORM/Mapping/OneToOne.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class OneToOne implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $targetEntity;
|
||||||
|
/** @var string */
|
||||||
|
public $mappedBy;
|
||||||
|
/** @var string */
|
||||||
|
public $inversedBy;
|
||||||
|
/** @var array<string> */
|
||||||
|
public $cascade;
|
||||||
|
/** @var string */
|
||||||
|
public $fetch = 'LAZY';
|
||||||
|
/** @var boolean */
|
||||||
|
public $orphanRemoval = false;
|
||||||
|
}
|
30
lib/Doctrine/ORM/Mapping/OrderBy.php
Normal file
30
lib/Doctrine/ORM/Mapping/OrderBy.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class OrderBy implements Annotation
|
||||||
|
{
|
||||||
|
/** @var array<string> */
|
||||||
|
public $value;
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/PostLoad.php
Normal file
28
lib/Doctrine/ORM/Mapping/PostLoad.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("METHOD")
|
||||||
|
*/
|
||||||
|
final class PostLoad implements Annotation
|
||||||
|
{
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/PostPersist.php
Normal file
28
lib/Doctrine/ORM/Mapping/PostPersist.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("METHOD")
|
||||||
|
*/
|
||||||
|
final class PostPersist implements Annotation
|
||||||
|
{
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/PostRemove.php
Normal file
28
lib/Doctrine/ORM/Mapping/PostRemove.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("METHOD")
|
||||||
|
*/
|
||||||
|
final class PostRemove implements Annotation
|
||||||
|
{
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/PostUpdate.php
Normal file
28
lib/Doctrine/ORM/Mapping/PostUpdate.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("METHOD")
|
||||||
|
*/
|
||||||
|
final class PostUpdate implements Annotation
|
||||||
|
{
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/PreFlush.php
Normal file
28
lib/Doctrine/ORM/Mapping/PreFlush.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("METHOD")
|
||||||
|
*/
|
||||||
|
final class PreFlush implements Annotation
|
||||||
|
{
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/PrePersist.php
Normal file
28
lib/Doctrine/ORM/Mapping/PrePersist.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("METHOD")
|
||||||
|
*/
|
||||||
|
final class PrePersist implements Annotation
|
||||||
|
{
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/PreRemove.php
Normal file
28
lib/Doctrine/ORM/Mapping/PreRemove.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("METHOD")
|
||||||
|
*/
|
||||||
|
final class PreRemove implements Annotation
|
||||||
|
{
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/PreUpdate.php
Normal file
28
lib/Doctrine/ORM/Mapping/PreUpdate.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("METHOD")
|
||||||
|
*/
|
||||||
|
final class PreUpdate implements Annotation
|
||||||
|
{
|
||||||
|
}
|
34
lib/Doctrine/ORM/Mapping/SequenceGenerator.php
Normal file
34
lib/Doctrine/ORM/Mapping/SequenceGenerator.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class SequenceGenerator implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $sequenceName;
|
||||||
|
/** @var integer */
|
||||||
|
public $allocationSize = 1;
|
||||||
|
/** @var integer */
|
||||||
|
public $initialValue = 1;
|
||||||
|
}
|
36
lib/Doctrine/ORM/Mapping/Table.php
Normal file
36
lib/Doctrine/ORM/Mapping/Table.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
*/
|
||||||
|
final class Table implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
/** @var string */
|
||||||
|
public $schema;
|
||||||
|
/** @var array<Doctrine\ORM\Mapping\Index> */
|
||||||
|
public $indexes;
|
||||||
|
/** @var array<Doctrine\ORM\Mapping\UniqueConstraint> */
|
||||||
|
public $uniqueConstraints;
|
||||||
|
}
|
32
lib/Doctrine/ORM/Mapping/UniqueConstraint.php
Normal file
32
lib/Doctrine/ORM/Mapping/UniqueConstraint.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("ANNOTATION")
|
||||||
|
*/
|
||||||
|
final class UniqueConstraint implements Annotation
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
/** @var array<string> */
|
||||||
|
public $columns;
|
||||||
|
}
|
28
lib/Doctrine/ORM/Mapping/Version.php
Normal file
28
lib/Doctrine/ORM/Mapping/Version.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many individuals
|
||||||
|
* and is licensed under the LGPL. For more information, see
|
||||||
|
* <http://www.doctrine-project.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Doctrine\ORM\Mapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @Target("PROPERTY")
|
||||||
|
*/
|
||||||
|
final class Version implements Annotation
|
||||||
|
{
|
||||||
|
}
|
@ -38,6 +38,7 @@ final class NativeQuery extends AbstractQuery
|
|||||||
public function setSQL($sql)
|
public function setSQL($sql)
|
||||||
{
|
{
|
||||||
$this->_sql = $sql;
|
$this->_sql = $sql;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,16 +59,18 @@ final class NativeQuery extends AbstractQuery
|
|||||||
protected function _doExecute()
|
protected function _doExecute()
|
||||||
{
|
{
|
||||||
$params = $this->_params;
|
$params = $this->_params;
|
||||||
$types = $this->_paramTypes;
|
$types = $this->_paramTypes;
|
||||||
if ($params) {
|
|
||||||
if (is_int(key($params))) {
|
if ($params && is_int(key($params))) {
|
||||||
ksort($params);
|
ksort($params);
|
||||||
ksort($types);
|
ksort($types);
|
||||||
$params = array_values($params);
|
|
||||||
$types = array_values($types);
|
$params = array_values($params);
|
||||||
}
|
$types = array_values($types);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->_em->getConnection()->executeQuery($this->_sql, $params, $types, $this->_queryCacheProfile);
|
return $this->_em->getConnection()->executeQuery(
|
||||||
|
$this->_sql, $params, $types, $this->_queryCacheProfile
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -144,4 +144,9 @@ class ORMException extends Exception
|
|||||||
return new self("Invalid repository class '".$className."'. ".
|
return new self("Invalid repository class '".$className."'. ".
|
||||||
"it must be a Doctrine\ORM\EntityRepository.");
|
"it must be a Doctrine\ORM\EntityRepository.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function missingIdentifierField($className, $fieldName)
|
||||||
|
{
|
||||||
|
return new self("The identifier $fieldName is missing for a query of " . $className);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ namespace Doctrine\ORM;
|
|||||||
|
|
||||||
use Doctrine\ORM\Mapping\ClassMetadata,
|
use Doctrine\ORM\Mapping\ClassMetadata,
|
||||||
Doctrine\Common\Collections\Collection,
|
Doctrine\Common\Collections\Collection,
|
||||||
|
Doctrine\Common\Collections\ArrayCollection,
|
||||||
Closure;
|
Closure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,8 +115,8 @@ final class PersistentCollection implements Collection
|
|||||||
*/
|
*/
|
||||||
public function __construct(EntityManager $em, $class, $coll)
|
public function __construct(EntityManager $em, $class, $coll)
|
||||||
{
|
{
|
||||||
$this->coll = $coll;
|
$this->coll = $coll;
|
||||||
$this->em = $em;
|
$this->em = $em;
|
||||||
$this->typeClass = $class;
|
$this->typeClass = $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,8 +130,8 @@ final class PersistentCollection implements Collection
|
|||||||
*/
|
*/
|
||||||
public function setOwner($entity, array $assoc)
|
public function setOwner($entity, array $assoc)
|
||||||
{
|
{
|
||||||
$this->owner = $entity;
|
$this->owner = $entity;
|
||||||
$this->association = $assoc;
|
$this->association = $assoc;
|
||||||
$this->backRefFieldName = $assoc['inversedBy'] ?: $assoc['mappedBy'];
|
$this->backRefFieldName = $assoc['inversedBy'] ?: $assoc['mappedBy'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,16 +161,18 @@ final class PersistentCollection implements Collection
|
|||||||
public function hydrateAdd($element)
|
public function hydrateAdd($element)
|
||||||
{
|
{
|
||||||
$this->coll->add($element);
|
$this->coll->add($element);
|
||||||
|
|
||||||
// If _backRefFieldName is set and its a one-to-many association,
|
// If _backRefFieldName is set and its a one-to-many association,
|
||||||
// we need to set the back reference.
|
// we need to set the back reference.
|
||||||
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) {
|
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
|
||||||
// Set back reference to owner
|
// Set back reference to owner
|
||||||
$this->typeClass->reflFields[$this->backRefFieldName]
|
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
|
||||||
->setValue($element, $this->owner);
|
$element, $this->owner
|
||||||
|
);
|
||||||
|
|
||||||
$this->em->getUnitOfWork()->setOriginalEntityProperty(
|
$this->em->getUnitOfWork()->setOriginalEntityProperty(
|
||||||
spl_object_hash($element),
|
spl_object_hash($element), $this->backRefFieldName, $this->owner
|
||||||
$this->backRefFieldName,
|
);
|
||||||
$this->owner);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,12 +186,14 @@ final class PersistentCollection implements Collection
|
|||||||
public function hydrateSet($key, $element)
|
public function hydrateSet($key, $element)
|
||||||
{
|
{
|
||||||
$this->coll->set($key, $element);
|
$this->coll->set($key, $element);
|
||||||
|
|
||||||
// If _backRefFieldName is set, then the association is bidirectional
|
// If _backRefFieldName is set, then the association is bidirectional
|
||||||
// and we need to set the back reference.
|
// and we need to set the back reference.
|
||||||
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) {
|
if ($this->backRefFieldName && $this->association['type'] === ClassMetadata::ONE_TO_MANY) {
|
||||||
// Set back reference to owner
|
// Set back reference to owner
|
||||||
$this->typeClass->reflFields[$this->backRefFieldName]
|
$this->typeClass->reflFields[$this->backRefFieldName]->setValue(
|
||||||
->setValue($element, $this->owner);
|
$element, $this->owner
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,23 +203,31 @@ final class PersistentCollection implements Collection
|
|||||||
*/
|
*/
|
||||||
public function initialize()
|
public function initialize()
|
||||||
{
|
{
|
||||||
if ( ! $this->initialized && $this->association) {
|
if ($this->initialized || ! $this->association) {
|
||||||
if ($this->isDirty) {
|
return;
|
||||||
// Has NEW objects added through add(). Remember them.
|
|
||||||
$newObjects = $this->coll->toArray();
|
|
||||||
}
|
|
||||||
$this->coll->clear();
|
|
||||||
$this->em->getUnitOfWork()->loadCollection($this);
|
|
||||||
$this->takeSnapshot();
|
|
||||||
// Reattach NEW objects added through add(), if any.
|
|
||||||
if (isset($newObjects)) {
|
|
||||||
foreach ($newObjects as $obj) {
|
|
||||||
$this->coll->add($obj);
|
|
||||||
}
|
|
||||||
$this->isDirty = true;
|
|
||||||
}
|
|
||||||
$this->initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has NEW objects added through add(). Remember them.
|
||||||
|
$newObjects = array();
|
||||||
|
|
||||||
|
if ($this->isDirty) {
|
||||||
|
$newObjects = $this->coll->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->coll->clear();
|
||||||
|
$this->em->getUnitOfWork()->loadCollection($this);
|
||||||
|
$this->takeSnapshot();
|
||||||
|
|
||||||
|
// Reattach NEW objects added through add(), if any.
|
||||||
|
if ($newObjects) {
|
||||||
|
foreach ($newObjects as $obj) {
|
||||||
|
$this->coll->add($obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->isDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,7 +237,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function takeSnapshot()
|
public function takeSnapshot()
|
||||||
{
|
{
|
||||||
$this->snapshot = $this->coll->toArray();
|
$this->snapshot = $this->coll->toArray();
|
||||||
$this->isDirty = false;
|
$this->isDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -246,8 +259,11 @@ final class PersistentCollection implements Collection
|
|||||||
*/
|
*/
|
||||||
public function getDeleteDiff()
|
public function getDeleteDiff()
|
||||||
{
|
{
|
||||||
return array_udiff_assoc($this->snapshot, $this->coll->toArray(),
|
return array_udiff_assoc(
|
||||||
function($a, $b) {return $a === $b ? 0 : 1;});
|
$this->snapshot,
|
||||||
|
$this->coll->toArray(),
|
||||||
|
function($a, $b) { return $a === $b ? 0 : 1; }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -258,8 +274,11 @@ final class PersistentCollection implements Collection
|
|||||||
*/
|
*/
|
||||||
public function getInsertDiff()
|
public function getInsertDiff()
|
||||||
{
|
{
|
||||||
return array_udiff_assoc($this->coll->toArray(), $this->snapshot,
|
return array_udiff_assoc(
|
||||||
function($a, $b) {return $a === $b ? 0 : 1;});
|
$this->coll->toArray(),
|
||||||
|
$this->snapshot,
|
||||||
|
function($a, $b) { return $a === $b ? 0 : 1; }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -277,12 +296,17 @@ final class PersistentCollection implements Collection
|
|||||||
*/
|
*/
|
||||||
private function changed()
|
private function changed()
|
||||||
{
|
{
|
||||||
if ( ! $this->isDirty) {
|
if ($this->isDirty) {
|
||||||
$this->isDirty = true;
|
return;
|
||||||
if ($this->association !== null && $this->association['isOwningSide'] && $this->association['type'] == ClassMetadata::MANY_TO_MANY &&
|
}
|
||||||
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
|
|
||||||
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
|
$this->isDirty = true;
|
||||||
}
|
|
||||||
|
if ($this->association !== null &&
|
||||||
|
$this->association['isOwningSide'] &&
|
||||||
|
$this->association['type'] === ClassMetadata::MANY_TO_MANY &&
|
||||||
|
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
|
||||||
|
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +355,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function first()
|
public function first()
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->first();
|
return $this->coll->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,6 +363,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function last()
|
public function last()
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->last();
|
return $this->coll->last();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,13 +377,19 @@ final class PersistentCollection implements Collection
|
|||||||
// not used we can issue a straight SQL delete/update on the
|
// not used we can issue a straight SQL delete/update on the
|
||||||
// association (table). Without initializing the collection.
|
// association (table). Without initializing the collection.
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
$removed = $this->coll->remove($key);
|
$removed = $this->coll->remove($key);
|
||||||
if ($removed) {
|
|
||||||
$this->changed();
|
if ( ! $removed) {
|
||||||
if ($this->association !== null && $this->association['type'] == ClassMetadata::ONE_TO_MANY &&
|
return $removed;
|
||||||
$this->association['orphanRemoval']) {
|
}
|
||||||
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
|
|
||||||
}
|
$this->changed();
|
||||||
|
|
||||||
|
if ($this->association !== null &&
|
||||||
|
$this->association['type'] == ClassMetadata::ONE_TO_MANY &&
|
||||||
|
$this->association['orphanRemoval']) {
|
||||||
|
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $removed;
|
return $removed;
|
||||||
@ -368,25 +400,36 @@ final class PersistentCollection implements Collection
|
|||||||
*/
|
*/
|
||||||
public function removeElement($element)
|
public function removeElement($element)
|
||||||
{
|
{
|
||||||
// TODO: Assuming the identity of entities in a collection is always based
|
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
|
||||||
// on their primary key (there is no equals/hashCode in PHP),
|
if ($this->coll->contains($element)) {
|
||||||
// if the collection is not initialized, we could issue a straight
|
return $this->coll->removeElement($element);
|
||||||
// SQL DELETE/UPDATE on the association (table) without initializing
|
}
|
||||||
// the collection.
|
|
||||||
/*if ( ! $this->initialized) {
|
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
|
||||||
$this->em->getUnitOfWork()->getCollectionPersister($this->association)
|
|
||||||
->deleteRows($this, $element);
|
if ($persister->removeElement($this, $element)) {
|
||||||
}*/
|
return $element;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
$removed = $this->coll->removeElement($element);
|
$removed = $this->coll->removeElement($element);
|
||||||
if ($removed) {
|
|
||||||
$this->changed();
|
if ( ! $removed) {
|
||||||
if ($this->association !== null && $this->association['type'] == ClassMetadata::ONE_TO_MANY &&
|
return $removed;
|
||||||
$this->association['orphanRemoval']) {
|
|
||||||
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->changed();
|
||||||
|
|
||||||
|
if ($this->association !== null &&
|
||||||
|
$this->association['type'] === ClassMetadata::ONE_TO_MANY &&
|
||||||
|
$this->association['orphanRemoval']) {
|
||||||
|
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
|
||||||
|
}
|
||||||
|
|
||||||
return $removed;
|
return $removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,6 +439,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function containsKey($key)
|
public function containsKey($key)
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->containsKey($key);
|
return $this->coll->containsKey($key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,14 +448,14 @@ final class PersistentCollection implements Collection
|
|||||||
*/
|
*/
|
||||||
public function contains($element)
|
public function contains($element)
|
||||||
{
|
{
|
||||||
if (!$this->initialized && $this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
|
if ( ! $this->initialized && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
|
||||||
return $this->coll->contains($element) ||
|
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
|
||||||
$this->em->getUnitOfWork()
|
|
||||||
->getCollectionPersister($this->association)
|
return $this->coll->contains($element) || $persister->contains($this, $element);
|
||||||
->contains($this, $element);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->contains($element);
|
return $this->coll->contains($element);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,6 +465,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function exists(Closure $p)
|
public function exists(Closure $p)
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->exists($p);
|
return $this->coll->exists($p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,6 +475,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function indexOf($element)
|
public function indexOf($element)
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->indexOf($element);
|
return $this->coll->indexOf($element);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,6 +485,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function get($key)
|
public function get($key)
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->get($key);
|
return $this->coll->get($key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,6 +495,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function getKeys()
|
public function getKeys()
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->getKeys();
|
return $this->coll->getKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,6 +505,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function getValues()
|
public function getValues()
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->getValues();
|
return $this->coll->getValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,13 +514,14 @@ final class PersistentCollection implements Collection
|
|||||||
*/
|
*/
|
||||||
public function count()
|
public function count()
|
||||||
{
|
{
|
||||||
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()
|
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
|
||||||
->getCollectionPersister($this->association)
|
|
||||||
->count($this) + ($this->isDirty ? $this->coll->count() : 0);
|
return $persister->count($this) + ($this->isDirty ? $this->coll->count() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->count();
|
return $this->coll->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,7 +531,9 @@ final class PersistentCollection implements Collection
|
|||||||
public function set($key, $value)
|
public function set($key, $value)
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
$this->coll->set($key, $value);
|
$this->coll->set($key, $value);
|
||||||
|
|
||||||
$this->changed();
|
$this->changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,7 +543,9 @@ final class PersistentCollection implements Collection
|
|||||||
public function add($value)
|
public function add($value)
|
||||||
{
|
{
|
||||||
$this->coll->add($value);
|
$this->coll->add($value);
|
||||||
|
|
||||||
$this->changed();
|
$this->changed();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,6 +555,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function isEmpty()
|
public function isEmpty()
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->isEmpty();
|
return $this->coll->isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,6 +565,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function getIterator()
|
public function getIterator()
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->getIterator();
|
return $this->coll->getIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,6 +575,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function map(Closure $func)
|
public function map(Closure $func)
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->map($func);
|
return $this->coll->map($func);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,6 +585,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function filter(Closure $p)
|
public function filter(Closure $p)
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->filter($p);
|
return $this->coll->filter($p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,6 +595,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function forAll(Closure $p)
|
public function forAll(Closure $p)
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->forAll($p);
|
return $this->coll->forAll($p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,6 +605,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function partition(Closure $p)
|
public function partition(Closure $p)
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->partition($p);
|
return $this->coll->partition($p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,6 +615,7 @@ final class PersistentCollection implements Collection
|
|||||||
public function toArray()
|
public function toArray()
|
||||||
{
|
{
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->toArray();
|
return $this->coll->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,19 +627,28 @@ final class PersistentCollection implements Collection
|
|||||||
if ($this->initialized && $this->isEmpty()) {
|
if ($this->initialized && $this->isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->association['type'] == ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
|
|
||||||
|
$uow = $this->em->getUnitOfWork();
|
||||||
|
|
||||||
|
if ($this->association['type'] === ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
|
||||||
// we need to initialize here, as orphan removal acts like implicit cascadeRemove,
|
// we need to initialize here, as orphan removal acts like implicit cascadeRemove,
|
||||||
// hence for event listeners we need the objects in memory.
|
// hence for event listeners we need the objects in memory.
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
foreach ($this->coll as $element) {
|
foreach ($this->coll as $element) {
|
||||||
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
|
$uow->scheduleOrphanRemoval($element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->coll->clear();
|
$this->coll->clear();
|
||||||
|
|
||||||
$this->initialized = true; // direct call, {@link initialize()} is too expensive
|
$this->initialized = true; // direct call, {@link initialize()} is too expensive
|
||||||
|
|
||||||
if ($this->association['isOwningSide']) {
|
if ($this->association['isOwningSide']) {
|
||||||
$this->changed();
|
$this->changed();
|
||||||
$this->em->getUnitOfWork()->scheduleCollectionDeletion($this);
|
|
||||||
|
$uow->scheduleCollectionDeletion($this);
|
||||||
|
|
||||||
$this->takeSnapshot();
|
$this->takeSnapshot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -622,6 +692,7 @@ final class PersistentCollection implements Collection
|
|||||||
if ( ! isset($offset)) {
|
if ( ! isset($offset)) {
|
||||||
return $this->add($value);
|
return $this->add($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->set($offset, $value);
|
return $this->set($offset, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -656,6 +727,8 @@ final class PersistentCollection implements Collection
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the wrapped Collection instance.
|
* Retrieves the wrapped Collection instance.
|
||||||
|
*
|
||||||
|
* @return Doctrine\Common\Collections\Collection
|
||||||
*/
|
*/
|
||||||
public function unwrap()
|
public function unwrap()
|
||||||
{
|
{
|
||||||
@ -671,20 +744,19 @@ final class PersistentCollection implements Collection
|
|||||||
*
|
*
|
||||||
* @param int $offset
|
* @param int $offset
|
||||||
* @param int $length
|
* @param int $length
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function slice($offset, $length = null)
|
public function slice($offset, $length = null)
|
||||||
{
|
{
|
||||||
if ( ! $this->initialized &&
|
if ( ! $this->initialized && ! $this->isDirty && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
|
||||||
! $this->isDirty &&
|
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
|
||||||
$this->association['fetch'] == Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY) {
|
|
||||||
|
|
||||||
return $this->em->getUnitOfWork()
|
return $persister->slice($this, $offset, $length);
|
||||||
->getCollectionPersister($this->association)
|
|
||||||
->slice($this, $offset, $length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->initialize();
|
$this->initialize();
|
||||||
|
|
||||||
return $this->coll->slice($offset, $length);
|
return $this->coll->slice($offset, $length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,6 +151,16 @@ abstract class AbstractCollectionPersister
|
|||||||
throw new \BadMethodCallException("Checking for existance of a key is not supported by this CollectionPersister.");
|
throw new \BadMethodCallException("Checking for existance of a key is not supported by this CollectionPersister.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function removeElement(PersistentCollection $coll, $element)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException("Removing an element is not supported by this CollectionPersister.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeKey(PersistentCollection $coll, $key)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException("Removing a key is not supported by this CollectionPersister.");
|
||||||
|
}
|
||||||
|
|
||||||
public function get(PersistentCollection $coll, $index)
|
public function get(PersistentCollection $coll, $index)
|
||||||
{
|
{
|
||||||
throw new \BadMethodCallException("Selecting a collection by index is not supported by this CollectionPersister.");
|
throw new \BadMethodCallException("Selecting a collection by index is not supported by this CollectionPersister.");
|
||||||
|
@ -28,8 +28,9 @@ use Doctrine\ORM\Mapping\ClassMetadata,
|
|||||||
/**
|
/**
|
||||||
* Persister for many-to-many collections.
|
* Persister for many-to-many collections.
|
||||||
*
|
*
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* @since 2.0
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
class ManyToManyPersister extends AbstractCollectionPersister
|
class ManyToManyPersister extends AbstractCollectionPersister
|
||||||
{
|
{
|
||||||
@ -80,8 +81,10 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
$columns = $mapping['joinTableColumns'];
|
$columns = $mapping['joinTableColumns'];
|
||||||
$class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
|
$class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
|
||||||
|
|
||||||
return 'INSERT INTO ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
|
$joinTable = $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform());
|
||||||
. ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
|
|
||||||
|
return 'INSERT INTO ' . $joinTable . ' (' . implode(', ', $columns) . ')'
|
||||||
|
. ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -119,27 +122,21 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
|
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
|
||||||
if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) {
|
$isRelationToSource = isset($mapping['relationToSourceKeyColumns'][$joinTableColumn]);
|
||||||
if ($isComposite) {
|
|
||||||
if ($class1->containsForeignIdentifier) {
|
if ( ! $isComposite) {
|
||||||
$params[] = $identifier1[$class1->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])];
|
$params[] = $isRelationToSource ? array_pop($identifier1) : array_pop($identifier2);
|
||||||
} else {
|
|
||||||
$params[] = $identifier1[$class1->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
|
continue;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$params[] = array_pop($identifier1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($isComposite) {
|
|
||||||
if ($class2->containsForeignIdentifier) {
|
|
||||||
$params[] = $identifier2[$class2->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])];
|
|
||||||
} else {
|
|
||||||
$params[] = $identifier2[$class2->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$params[] = array_pop($identifier2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($isRelationToSource) {
|
||||||
|
$params[] = $identifier1[$class1->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])];
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params[] = $identifier2[$class2->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $params;
|
return $params;
|
||||||
@ -152,19 +149,11 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
*/
|
*/
|
||||||
protected function _getDeleteSQL(PersistentCollection $coll)
|
protected function _getDeleteSQL(PersistentCollection $coll)
|
||||||
{
|
{
|
||||||
$mapping = $coll->getMapping();
|
$class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
|
||||||
$class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
|
$mapping = $coll->getMapping();
|
||||||
$joinTable = $mapping['joinTable'];
|
|
||||||
$whereClause = '';
|
|
||||||
|
|
||||||
foreach ($mapping['relationToSourceKeyColumns'] as $relationColumn => $srcColumn) {
|
|
||||||
if ($whereClause !== '') $whereClause .= ' AND ';
|
|
||||||
|
|
||||||
$whereClause .= $relationColumn . ' = ?';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
|
return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
|
||||||
. ' WHERE ' . $whereClause;
|
. ' WHERE ' . implode(' = ? AND ', array_keys($mapping['relationToSourceKeyColumns'])) . ' = ?';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,18 +165,22 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
*/
|
*/
|
||||||
protected function _getDeleteSQLParameters(PersistentCollection $coll)
|
protected function _getDeleteSQLParameters(PersistentCollection $coll)
|
||||||
{
|
{
|
||||||
$params = array();
|
|
||||||
$mapping = $coll->getMapping();
|
|
||||||
$identifier = $this->_uow->getEntityIdentifier($coll->getOwner());
|
$identifier = $this->_uow->getEntityIdentifier($coll->getOwner());
|
||||||
|
$mapping = $coll->getMapping();
|
||||||
|
$params = array();
|
||||||
|
|
||||||
if (count($mapping['relationToSourceKeyColumns']) > 1) {
|
// Optimization for single column identifier
|
||||||
$sourceClass = $this->_em->getClassMetadata(get_class($mapping->getOwner()));
|
if (count($mapping['relationToSourceKeyColumns']) === 1) {
|
||||||
|
$params[] = array_pop($identifier);
|
||||||
|
|
||||||
foreach ($mapping['relationToSourceKeyColumns'] as $relColumn => $srcColumn) {
|
return $params;
|
||||||
$params[] = $identifier[$sourceClass->fieldNames[$srcColumn]];
|
}
|
||||||
}
|
|
||||||
} else {
|
// Composite identifier
|
||||||
$params[] = array_pop($identifier);
|
$sourceClass = $this->_em->getClassMetadata(get_class($mapping->getOwner()));
|
||||||
|
|
||||||
|
foreach ($mapping['relationToSourceKeyColumns'] as $relColumn => $srcColumn) {
|
||||||
|
$params[] = $identifier[$sourceClass->fieldNames[$srcColumn]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $params;
|
return $params;
|
||||||
@ -198,7 +191,6 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
*/
|
*/
|
||||||
public function count(PersistentCollection $coll)
|
public function count(PersistentCollection $coll)
|
||||||
{
|
{
|
||||||
$params = array();
|
|
||||||
$mapping = $coll->getMapping();
|
$mapping = $coll->getMapping();
|
||||||
$class = $this->_em->getClassMetadata($mapping['sourceEntity']);
|
$class = $this->_em->getClassMetadata($mapping['sourceEntity']);
|
||||||
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
|
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
|
||||||
@ -210,28 +202,30 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
$joinColumns = $mapping['relationToTargetKeyColumns'];
|
$joinColumns = $mapping['relationToTargetKeyColumns'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$whereClause = '';
|
$whereClauses = array();
|
||||||
|
$params = array();
|
||||||
|
|
||||||
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
|
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
|
||||||
if (isset($joinColumns[$joinTableColumn])) {
|
if ( ! isset($joinColumns[$joinTableColumn])) {
|
||||||
if ($whereClause !== '') {
|
continue;
|
||||||
$whereClause .= ' AND ';
|
|
||||||
}
|
|
||||||
$whereClause .= "t.$joinTableColumn = ?";
|
|
||||||
|
|
||||||
$params[] = ($class->containsForeignIdentifier)
|
|
||||||
? $id[$class->getFieldForColumn($joinColumns[$joinTableColumn])]
|
|
||||||
: $id[$class->fieldNames[$joinColumns[$joinTableColumn]]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$whereClauses[] = $joinTableColumn . ' = ?';
|
||||||
|
|
||||||
|
$params[] = ($class->containsForeignIdentifier)
|
||||||
|
? $id[$class->getFieldForColumn($joinColumns[$joinTableColumn])]
|
||||||
|
: $id[$class->fieldNames[$joinColumns[$joinTableColumn]]];
|
||||||
}
|
}
|
||||||
|
|
||||||
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
|
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
|
||||||
|
if('' !== $filterSql) {
|
||||||
|
$whereClauses[] = $filterSql;
|
||||||
|
}
|
||||||
|
|
||||||
$sql = 'SELECT COUNT(*)'
|
$sql = 'SELECT COUNT(*)'
|
||||||
. ' FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) . ' t'
|
. ' FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) . ' t'
|
||||||
. $joinTargetEntitySQL
|
. $joinTargetEntitySQL
|
||||||
. ' WHERE ' . $whereClause
|
. ' WHERE ' . implode(' AND ', $whereClauses);
|
||||||
. $filterSql;
|
|
||||||
|
|
||||||
return $this->_conn->fetchColumn($sql, $params);
|
return $this->_conn->fetchColumn($sql, $params);
|
||||||
}
|
}
|
||||||
@ -252,6 +246,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
/**
|
/**
|
||||||
* @param PersistentCollection $coll
|
* @param PersistentCollection $coll
|
||||||
* @param object $element
|
* @param object $element
|
||||||
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function contains(PersistentCollection $coll, $element)
|
public function contains(PersistentCollection $coll, $element)
|
||||||
{
|
{
|
||||||
@ -262,7 +257,43 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$params = array();
|
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, $element, true);
|
||||||
|
|
||||||
|
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
|
||||||
|
|
||||||
|
return (bool) $this->_conn->fetchColumn($sql, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param PersistentCollection $coll
|
||||||
|
* @param object $element
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function removeElement(PersistentCollection $coll, $element)
|
||||||
|
{
|
||||||
|
$uow = $this->_em->getUnitOfWork();
|
||||||
|
|
||||||
|
// shortcut for new entities
|
||||||
|
if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($coll, $element, false);
|
||||||
|
|
||||||
|
$sql = 'DELETE FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
|
||||||
|
|
||||||
|
return (bool) $this->_conn->executeUpdate($sql, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Doctrine\ORM\PersistentCollection $coll
|
||||||
|
* @param object $element
|
||||||
|
* @param boolean $addFilters Whether the filter SQL should be included or not.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getJoinTableRestrictions(PersistentCollection $coll, $element, $addFilters)
|
||||||
|
{
|
||||||
|
$uow = $this->_em->getUnitOfWork();
|
||||||
$mapping = $coll->getMapping();
|
$mapping = $coll->getMapping();
|
||||||
|
|
||||||
if ( ! $mapping['isOwningSide']) {
|
if ( ! $mapping['isOwningSide']) {
|
||||||
@ -279,41 +310,35 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
$targetId = $uow->getEntityIdentifier($element);
|
$targetId = $uow->getEntityIdentifier($element);
|
||||||
}
|
}
|
||||||
|
|
||||||
$whereClause = '';
|
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform());
|
||||||
|
$whereClauses = array();
|
||||||
|
$params = array();
|
||||||
|
|
||||||
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
|
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
|
||||||
|
$whereClauses[] = $joinTableColumn . ' = ?';
|
||||||
|
|
||||||
if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) {
|
if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) {
|
||||||
if ($whereClause !== '') {
|
|
||||||
$whereClause .= ' AND ';
|
|
||||||
}
|
|
||||||
|
|
||||||
$whereClause .= $joinTableColumn . ' = ?';
|
|
||||||
|
|
||||||
$params[] = ($targetClass->containsForeignIdentifier)
|
$params[] = ($targetClass->containsForeignIdentifier)
|
||||||
? $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]
|
? $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]
|
||||||
: $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
|
: $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
|
||||||
} else if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) {
|
continue;
|
||||||
if ($whereClause !== '') {
|
}
|
||||||
$whereClause .= ' AND ';
|
|
||||||
}
|
|
||||||
|
|
||||||
$whereClause .= $joinTableColumn . ' = ?';
|
// relationToSourceKeyColumns
|
||||||
|
$params[] = ($sourceClass->containsForeignIdentifier)
|
||||||
|
? $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])]
|
||||||
|
: $sourceId[$sourceClass->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
|
||||||
|
}
|
||||||
|
|
||||||
$params[] = ($sourceClass->containsForeignIdentifier)
|
if($addFilters) {
|
||||||
? $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])]
|
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
|
||||||
: $sourceId[$sourceClass->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
|
if('' !== $filterSql) {
|
||||||
|
$quotedJoinTable .= ' t ' . $joinTargetEntitySQL;
|
||||||
|
$whereClauses[] = $filterSql;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
|
return array($quotedJoinTable, $whereClauses, $params);
|
||||||
|
|
||||||
$sql = 'SELECT 1'
|
|
||||||
. ' FROM ' . $sourceClass->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform()) . ' t'
|
|
||||||
. $joinTargetEntitySQL
|
|
||||||
. ' WHERE ' . $whereClause
|
|
||||||
. $filterSql;
|
|
||||||
|
|
||||||
return (bool) $this->_conn->fetchColumn($sql, $params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -356,9 +381,11 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
|||||||
{
|
{
|
||||||
$filterSql = '';
|
$filterSql = '';
|
||||||
|
|
||||||
|
$first = true;
|
||||||
foreach($this->_em->getFilters()->getEnabledFilters() as $filter) {
|
foreach($this->_em->getFilters()->getEnabledFilters() as $filter) {
|
||||||
if('' !== $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) {
|
if('' !== $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) {
|
||||||
$filterSql .= 'AND (' . $filterExpr . ')';
|
if($first) $first = false; else $filterSql .= ' AND ';
|
||||||
|
$filterSql .= '(' . $filterExpr . ')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,13 +27,9 @@ use Doctrine\ORM\PersistentCollection,
|
|||||||
/**
|
/**
|
||||||
* Persister for one-to-many collections.
|
* Persister for one-to-many collections.
|
||||||
*
|
*
|
||||||
* IMPORTANT:
|
* @author Roman Borschel <roman@code-factory.org>
|
||||||
* This persister is only used for uni-directional one-to-many mappings on a foreign key
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||||
* (which are not yet supported). So currently this persister is not used.
|
* @since 2.0
|
||||||
*
|
|
||||||
* @since 2.0
|
|
||||||
* @author Roman Borschel <roman@code-factory.org>
|
|
||||||
* @todo Remove
|
|
||||||
*/
|
*/
|
||||||
class OneToManyPersister extends AbstractCollectionPersister
|
class OneToManyPersister extends AbstractCollectionPersister
|
||||||
{
|
{
|
||||||
@ -48,24 +44,19 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||||||
protected function _getDeleteRowSQL(PersistentCollection $coll)
|
protected function _getDeleteRowSQL(PersistentCollection $coll)
|
||||||
{
|
{
|
||||||
$mapping = $coll->getMapping();
|
$mapping = $coll->getMapping();
|
||||||
$targetClass = $this->_em->getClassMetadata($mapping->getTargetEntityName());
|
$class = $this->_em->getClassMetadata($mapping['targetEntity']);
|
||||||
$table = $targetClass->getTableName();
|
|
||||||
|
|
||||||
$ownerMapping = $targetClass->getAssociationMapping($mapping['mappedBy']);
|
return 'DELETE FROM ' . $class->getQuotedTableName($this->_conn->getDatabasePlatform())
|
||||||
|
. ' WHERE ' . implode('= ? AND ', $class->getIdentifierColumnNames()) . ' = ?';
|
||||||
|
}
|
||||||
|
|
||||||
$setClause = '';
|
/**
|
||||||
foreach ($ownerMapping->sourceToTargetKeyColumns as $sourceCol => $targetCol) {
|
* {@inheritdoc}
|
||||||
if ($setClause != '') $setClause .= ', ';
|
*
|
||||||
$setClause .= "$sourceCol = NULL";
|
*/
|
||||||
}
|
protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element)
|
||||||
|
{
|
||||||
$whereClause = '';
|
return array_values($this->_uow->getEntityIdentifier($element));
|
||||||
foreach ($targetClass->getIdentifierColumnNames() as $idColumn) {
|
|
||||||
if ($whereClause != '') $whereClause .= ' AND ';
|
|
||||||
$whereClause .= "$idColumn = ?";
|
|
||||||
}
|
|
||||||
|
|
||||||
return array("UPDATE $table SET $setClause WHERE $whereClause", $this->_uow->getEntityIdentifier($element));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _getInsertRowSQL(PersistentCollection $coll)
|
protected function _getInsertRowSQL(PersistentCollection $coll)
|
||||||
@ -73,6 +64,16 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||||||
return "UPDATE xxx SET foreign_key = yyy WHERE foreign_key = zzz";
|
return "UPDATE xxx SET foreign_key = yyy WHERE foreign_key = zzz";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the SQL parameters for the corresponding SQL statement to insert the given
|
||||||
|
* element of the given collection into the database.
|
||||||
|
*
|
||||||
|
* @param PersistentCollection $coll
|
||||||
|
* @param mixed $element
|
||||||
|
*/
|
||||||
|
protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element)
|
||||||
|
{}
|
||||||
|
|
||||||
/* Not used for OneToManyPersister */
|
/* Not used for OneToManyPersister */
|
||||||
protected function _getUpdateRowSQL(PersistentCollection $coll)
|
protected function _getUpdateRowSQL(PersistentCollection $coll)
|
||||||
{
|
{
|
||||||
@ -98,60 +99,37 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||||||
protected function _getDeleteSQLParameters(PersistentCollection $coll)
|
protected function _getDeleteSQLParameters(PersistentCollection $coll)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the SQL parameters for the corresponding SQL statement to insert the given
|
|
||||||
* element of the given collection into the database.
|
|
||||||
*
|
|
||||||
* @param PersistentCollection $coll
|
|
||||||
* @param mixed $element
|
|
||||||
*/
|
|
||||||
protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the SQL parameters for the corresponding SQL statement to delete the given
|
|
||||||
* element from the given collection.
|
|
||||||
*
|
|
||||||
* @param PersistentCollection $coll
|
|
||||||
* @param mixed $element
|
|
||||||
*/
|
|
||||||
protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function count(PersistentCollection $coll)
|
public function count(PersistentCollection $coll)
|
||||||
{
|
{
|
||||||
$mapping = $coll->getMapping();
|
$mapping = $coll->getMapping();
|
||||||
$targetClass = $this->_em->getClassMetadata($mapping['targetEntity']);
|
$targetClass = $this->_em->getClassMetadata($mapping['targetEntity']);
|
||||||
$sourceClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
|
$sourceClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
|
||||||
|
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
|
||||||
|
|
||||||
$params = array();
|
$whereClauses = array();
|
||||||
$id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
|
$params = array();
|
||||||
|
|
||||||
$where = '';
|
|
||||||
foreach ($targetClass->associationMappings[$mapping['mappedBy']]['joinColumns'] AS $joinColumn) {
|
foreach ($targetClass->associationMappings[$mapping['mappedBy']]['joinColumns'] AS $joinColumn) {
|
||||||
if ($where != '') {
|
$whereClauses[] = $joinColumn['name'] . ' = ?';
|
||||||
$where .= ' AND ';
|
|
||||||
}
|
$params[] = ($targetClass->containsForeignIdentifier)
|
||||||
$where .= "t." . $joinColumn['name'] . " = ?";
|
? $id[$sourceClass->getFieldForColumn($joinColumn['referencedColumnName'])]
|
||||||
if ($targetClass->containsForeignIdentifier) {
|
: $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]];
|
||||||
$params[] = $id[$sourceClass->getFieldForColumn($joinColumn['referencedColumnName'])];
|
|
||||||
} else {
|
|
||||||
$params[] = $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "SELECT count(*) FROM " . $targetClass->getQuotedTableName($this->_conn->getDatabasePlatform()) . " t WHERE " . $where;
|
|
||||||
|
|
||||||
// Apply the filters
|
|
||||||
foreach($this->_em->getFilters()->getEnabledFilters() as $filter) {
|
foreach($this->_em->getFilters()->getEnabledFilters() as $filter) {
|
||||||
if("" !== $filterExpr = $filter->addFilterConstraint($targetClass, 't')) {
|
if("" !== $filterExpr = $filter->addFilterConstraint($targetClass, 't')) {
|
||||||
$sql .= ' AND (' . $filterExpr . ')';
|
$whereClauses[] = '(' . $filterExpr . ')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sql = 'SELECT count(*)'
|
||||||
|
. ' FROM ' . $targetClass->getQuotedTableName($this->_conn->getDatabasePlatform()) . ' t'
|
||||||
|
. ' WHERE ' . implode(' AND ', $whereClauses);
|
||||||
|
|
||||||
return $this->_conn->fetchColumn($sql, $params);
|
return $this->_conn->fetchColumn($sql, $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,19 +141,45 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||||||
*/
|
*/
|
||||||
public function slice(PersistentCollection $coll, $offset, $length = null)
|
public function slice(PersistentCollection $coll, $offset, $length = null)
|
||||||
{
|
{
|
||||||
$mapping = $coll->getMapping();
|
$mapping = $coll->getMapping();
|
||||||
return $this->_em->getUnitOfWork()
|
$uow = $this->_em->getUnitOfWork();
|
||||||
->getEntityPersister($mapping['targetEntity'])
|
$persister = $uow->getEntityPersister($mapping['targetEntity']);
|
||||||
->getOneToManyCollection($mapping, $coll->getOwner(), $offset, $length);
|
|
||||||
|
return $persister->getOneToManyCollection($mapping, $coll->getOwner(), $offset, $length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param PersistentCollection $coll
|
* @param PersistentCollection $coll
|
||||||
* @param object $element
|
* @param object $element
|
||||||
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function contains(PersistentCollection $coll, $element)
|
public function contains(PersistentCollection $coll, $element)
|
||||||
{
|
{
|
||||||
$mapping = $coll->getMapping();
|
$mapping = $coll->getMapping();
|
||||||
|
$uow = $this->_em->getUnitOfWork();
|
||||||
|
|
||||||
|
// shortcut for new entities
|
||||||
|
if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$persister = $uow->getEntityPersister($mapping['targetEntity']);
|
||||||
|
|
||||||
|
// only works with single id identifier entities. Will throw an
|
||||||
|
// exception in Entity Persisters if that is not the case for the
|
||||||
|
// 'mappedBy' field.
|
||||||
|
$id = current( $uow->getEntityIdentifier($coll->getOwner()) );
|
||||||
|
|
||||||
|
return $persister->exists($element, array($mapping['mappedBy'] => $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param PersistentCollection $coll
|
||||||
|
* @param object $element
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function removeElement(PersistentCollection $coll, $element)
|
||||||
|
{
|
||||||
$uow = $this->_em->getUnitOfWork();
|
$uow = $this->_em->getUnitOfWork();
|
||||||
|
|
||||||
// shortcut for new entities
|
// shortcut for new entities
|
||||||
@ -183,11 +187,11 @@ class OneToManyPersister extends AbstractCollectionPersister
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only works with single id identifier entities. Will throw an exception in Entity Persisters
|
$mapping = $coll->getMapping();
|
||||||
// if that is not the case for the 'mappedBy' field.
|
$class = $this->_em->getClassMetadata($mapping['targetEntity']);
|
||||||
$id = current( $uow->getEntityIdentifier($coll->getOwner()) );
|
$sql = 'DELETE FROM ' . $class->getQuotedTableName($this->_conn->getDatabasePlatform())
|
||||||
|
. ' WHERE ' . implode('= ? AND ', $class->getIdentifierColumnNames()) . ' = ?';
|
||||||
|
|
||||||
return $uow->getEntityPersister($mapping['targetEntity'])
|
return (bool) $this->_conn->executeUpdate($sql, $this->_getDeleteRowSQLParameters($coll, $element));
|
||||||
->exists($element, array($mapping['mappedBy'] => $id));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,26 +205,30 @@ final class Query extends AbstractQuery
|
|||||||
return $this->_parserResult;
|
return $this->_parserResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check query cache.
|
$this->_state = self::STATE_CLEAN;
|
||||||
if ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver())) {
|
|
||||||
$hash = $this->_getQueryCacheId();
|
|
||||||
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
|
|
||||||
|
|
||||||
if ($cached === false) {
|
// Check query cache.
|
||||||
// Cache miss.
|
if ( ! ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver()))) {
|
||||||
$parser = new Parser($this);
|
|
||||||
$this->_parserResult = $parser->parse();
|
|
||||||
$queryCache->save($hash, $this->_parserResult, $this->_queryCacheTTL);
|
|
||||||
} else {
|
|
||||||
// Cache hit.
|
|
||||||
$this->_parserResult = $cached;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$parser = new Parser($this);
|
$parser = new Parser($this);
|
||||||
$this->_parserResult = $parser->parse();
|
$this->_parserResult = $parser->parse();
|
||||||
|
|
||||||
|
return $this->_parserResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_state = self::STATE_CLEAN;
|
$hash = $this->_getQueryCacheId();
|
||||||
|
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
|
||||||
|
|
||||||
|
if ($cached !== false) {
|
||||||
|
// Cache hit.
|
||||||
|
$this->_parserResult = $cached;
|
||||||
|
|
||||||
|
return $this->_parserResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache miss.
|
||||||
|
$parser = new Parser($this);
|
||||||
|
$this->_parserResult = $parser->parse();
|
||||||
|
$queryCache->save($hash, $this->_parserResult, $this->_queryCacheTTL);
|
||||||
|
|
||||||
return $this->_parserResult;
|
return $this->_parserResult;
|
||||||
}
|
}
|
||||||
@ -235,6 +239,7 @@ final class Query extends AbstractQuery
|
|||||||
protected function _doExecute()
|
protected function _doExecute()
|
||||||
{
|
{
|
||||||
$executor = $this->_parse()->getSqlExecutor();
|
$executor = $this->_parse()->getSqlExecutor();
|
||||||
|
|
||||||
if ($this->_queryCacheProfile) {
|
if ($this->_queryCacheProfile) {
|
||||||
$executor->setQueryCacheProfile($this->_queryCacheProfile);
|
$executor->setQueryCacheProfile($this->_queryCacheProfile);
|
||||||
}
|
}
|
||||||
@ -342,6 +347,7 @@ final class Query extends AbstractQuery
|
|||||||
public function setQueryCacheDriver($queryCache)
|
public function setQueryCacheDriver($queryCache)
|
||||||
{
|
{
|
||||||
$this->_queryCache = $queryCache;
|
$this->_queryCache = $queryCache;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,6 +360,7 @@ final class Query extends AbstractQuery
|
|||||||
public function useQueryCache($bool)
|
public function useQueryCache($bool)
|
||||||
{
|
{
|
||||||
$this->_useQueryCache = $bool;
|
$this->_useQueryCache = $bool;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,9 +374,9 @@ final class Query extends AbstractQuery
|
|||||||
{
|
{
|
||||||
if ($this->_queryCache) {
|
if ($this->_queryCache) {
|
||||||
return $this->_queryCache;
|
return $this->_queryCache;
|
||||||
} else {
|
|
||||||
return $this->_em->getConfiguration()->getQueryCacheImpl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->_em->getConfiguration()->getQueryCacheImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -383,6 +390,7 @@ final class Query extends AbstractQuery
|
|||||||
if ($timeToLive !== null) {
|
if ($timeToLive !== null) {
|
||||||
$timeToLive = (int) $timeToLive;
|
$timeToLive = (int) $timeToLive;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_queryCacheTTL = $timeToLive;
|
$this->_queryCacheTTL = $timeToLive;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
@ -427,6 +435,7 @@ final class Query extends AbstractQuery
|
|||||||
public function free()
|
public function free()
|
||||||
{
|
{
|
||||||
parent::free();
|
parent::free();
|
||||||
|
|
||||||
$this->_dql = null;
|
$this->_dql = null;
|
||||||
$this->_state = self::STATE_CLEAN;
|
$this->_state = self::STATE_CLEAN;
|
||||||
}
|
}
|
||||||
@ -443,6 +452,7 @@ final class Query extends AbstractQuery
|
|||||||
$this->_dql = $dqlQuery;
|
$this->_dql = $dqlQuery;
|
||||||
$this->_state = self::STATE_DIRTY;
|
$this->_state = self::STATE_DIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,6 +502,7 @@ final class Query extends AbstractQuery
|
|||||||
{
|
{
|
||||||
$this->_firstResult = $firstResult;
|
$this->_firstResult = $firstResult;
|
||||||
$this->_state = self::STATE_DIRTY;
|
$this->_state = self::STATE_DIRTY;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,6 +527,7 @@ final class Query extends AbstractQuery
|
|||||||
{
|
{
|
||||||
$this->_maxResults = $maxResults;
|
$this->_maxResults = $maxResults;
|
||||||
$this->_state = self::STATE_DIRTY;
|
$this->_state = self::STATE_DIRTY;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,6 +553,7 @@ final class Query extends AbstractQuery
|
|||||||
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
|
public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_OBJECT)
|
||||||
{
|
{
|
||||||
$this->setHint(self::HINT_INTERNAL_ITERATION, true);
|
$this->setHint(self::HINT_INTERNAL_ITERATION, true);
|
||||||
|
|
||||||
return parent::iterate($params, $hydrationMode);
|
return parent::iterate($params, $hydrationMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,6 +563,7 @@ final class Query extends AbstractQuery
|
|||||||
public function setHint($name, $value)
|
public function setHint($name, $value)
|
||||||
{
|
{
|
||||||
$this->_state = self::STATE_DIRTY;
|
$this->_state = self::STATE_DIRTY;
|
||||||
|
|
||||||
return parent::setHint($name, $value);
|
return parent::setHint($name, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,6 +573,7 @@ final class Query extends AbstractQuery
|
|||||||
public function setHydrationMode($hydrationMode)
|
public function setHydrationMode($hydrationMode)
|
||||||
{
|
{
|
||||||
$this->_state = self::STATE_DIRTY;
|
$this->_state = self::STATE_DIRTY;
|
||||||
|
|
||||||
return parent::setHydrationMode($hydrationMode);
|
return parent::setHydrationMode($hydrationMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,13 +586,14 @@ final class Query extends AbstractQuery
|
|||||||
*/
|
*/
|
||||||
public function setLockMode($lockMode)
|
public function setLockMode($lockMode)
|
||||||
{
|
{
|
||||||
if ($lockMode == LockMode::PESSIMISTIC_READ || $lockMode == LockMode::PESSIMISTIC_WRITE) {
|
if ($lockMode === LockMode::PESSIMISTIC_READ || $lockMode === LockMode::PESSIMISTIC_WRITE) {
|
||||||
if (!$this->_em->getConnection()->isTransactionActive()) {
|
if ( ! $this->_em->getConnection()->isTransactionActive()) {
|
||||||
throw TransactionRequiredException::transactionRequired();
|
throw TransactionRequiredException::transactionRequired();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setHint(self::HINT_LOCK_MODE, $lockMode);
|
$this->setHint(self::HINT_LOCK_MODE, $lockMode);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,9 +605,11 @@ final class Query extends AbstractQuery
|
|||||||
public function getLockMode()
|
public function getLockMode()
|
||||||
{
|
{
|
||||||
$lockMode = $this->getHint(self::HINT_LOCK_MODE);
|
$lockMode = $this->getHint(self::HINT_LOCK_MODE);
|
||||||
if (!$lockMode) {
|
|
||||||
|
if ( ! $lockMode) {
|
||||||
return LockMode::NONE;
|
return LockMode::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $lockMode;
|
return $lockMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,6 +640,7 @@ final class Query extends AbstractQuery
|
|||||||
public function __clone()
|
public function __clone()
|
||||||
{
|
{
|
||||||
parent::__clone();
|
parent::__clone();
|
||||||
|
|
||||||
$this->_state = self::STATE_DIRTY;
|
$this->_state = self::STATE_DIRTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,13 @@ namespace Doctrine\ORM\Query\AST;
|
|||||||
class InExpression extends Node
|
class InExpression extends Node
|
||||||
{
|
{
|
||||||
public $not;
|
public $not;
|
||||||
public $pathExpression;
|
public $expression;
|
||||||
public $literals = array();
|
public $literals = array();
|
||||||
public $subselect;
|
public $subselect;
|
||||||
|
|
||||||
public function __construct($pathExpression)
|
public function __construct($expression)
|
||||||
{
|
{
|
||||||
$this->pathExpression = $pathExpression;
|
$this->expression = $expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch($sqlWalker)
|
public function dispatch($sqlWalker)
|
||||||
|
@ -149,50 +149,58 @@ class Lexer extends \Doctrine\Common\Lexer
|
|||||||
{
|
{
|
||||||
$type = self::T_NONE;
|
$type = self::T_NONE;
|
||||||
|
|
||||||
// Recognizing numeric values
|
switch (true) {
|
||||||
if (is_numeric($value)) {
|
// Recognize numeric values
|
||||||
return (strpos($value, '.') !== false || stripos($value, 'e') !== false)
|
case (is_numeric($value)):
|
||||||
? self::T_FLOAT : self::T_INTEGER;
|
if (strpos($value, '.') !== false || stripos($value, 'e') !== false) {
|
||||||
}
|
return self::T_FLOAT;
|
||||||
|
|
||||||
// Differentiate between quoted names, identifiers, input parameters and symbols
|
|
||||||
if ($value[0] === "'") {
|
|
||||||
$value = str_replace("''", "'", substr($value, 1, strlen($value) - 2));
|
|
||||||
return self::T_STRING;
|
|
||||||
} else if (ctype_alpha($value[0]) || $value[0] === '_') {
|
|
||||||
$name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($value);
|
|
||||||
|
|
||||||
if (defined($name)) {
|
|
||||||
$type = constant($name);
|
|
||||||
|
|
||||||
if ($type > 100) {
|
|
||||||
return $type;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return self::T_IDENTIFIER;
|
return self::T_INTEGER;
|
||||||
} else if ($value[0] === '?' || $value[0] === ':') {
|
|
||||||
return self::T_INPUT_PARAMETER;
|
// Recognize quoted strings
|
||||||
} else {
|
case ($value[0] === "'"):
|
||||||
switch ($value) {
|
$value = str_replace("''", "'", substr($value, 1, strlen($value) - 2));
|
||||||
case '.': return self::T_DOT;
|
|
||||||
case ',': return self::T_COMMA;
|
return self::T_STRING;
|
||||||
case '(': return self::T_OPEN_PARENTHESIS;
|
|
||||||
case ')': return self::T_CLOSE_PARENTHESIS;
|
// Recognize identifiers
|
||||||
case '=': return self::T_EQUALS;
|
case (ctype_alpha($value[0]) || $value[0] === '_'):
|
||||||
case '>': return self::T_GREATER_THAN;
|
$name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($value);
|
||||||
case '<': return self::T_LOWER_THAN;
|
|
||||||
case '+': return self::T_PLUS;
|
if (defined($name)) {
|
||||||
case '-': return self::T_MINUS;
|
$type = constant($name);
|
||||||
case '*': return self::T_MULTIPLY;
|
|
||||||
case '/': return self::T_DIVIDE;
|
if ($type > 100) {
|
||||||
case '!': return self::T_NEGATE;
|
return $type;
|
||||||
case '{': return self::T_OPEN_CURLY_BRACE;
|
}
|
||||||
case '}': return self::T_CLOSE_CURLY_BRACE;
|
}
|
||||||
default:
|
|
||||||
// Do nothing
|
return self::T_IDENTIFIER;
|
||||||
break;
|
|
||||||
}
|
// Recognize input parameters
|
||||||
|
case ($value[0] === '?' || $value[0] === ':'):
|
||||||
|
return self::T_INPUT_PARAMETER;
|
||||||
|
|
||||||
|
// Recognize symbols
|
||||||
|
case ($value === '.'): return self::T_DOT;
|
||||||
|
case ($value === ','): return self::T_COMMA;
|
||||||
|
case ($value === '('): return self::T_OPEN_PARENTHESIS;
|
||||||
|
case ($value === ')'): return self::T_CLOSE_PARENTHESIS;
|
||||||
|
case ($value === '='): return self::T_EQUALS;
|
||||||
|
case ($value === '>'): return self::T_GREATER_THAN;
|
||||||
|
case ($value === '<'): return self::T_LOWER_THAN;
|
||||||
|
case ($value === '+'): return self::T_PLUS;
|
||||||
|
case ($value === '-'): return self::T_MINUS;
|
||||||
|
case ($value === '*'): return self::T_MULTIPLY;
|
||||||
|
case ($value === '/'): return self::T_DIVIDE;
|
||||||
|
case ($value === '!'): return self::T_NEGATE;
|
||||||
|
case ($value === '{'): return self::T_OPEN_CURLY_BRACE;
|
||||||
|
case ($value === '}'): return self::T_CLOSE_CURLY_BRACE;
|
||||||
|
|
||||||
|
// Default
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
return $type;
|
return $type;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* 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 MERCHARNTABILITY AND FITNESS FOR
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
@ -677,13 +677,10 @@ class Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build the error message
|
// Build the error message
|
||||||
$semanticalError = 'Invalid PathExpression. ';
|
$semanticalError = 'Invalid PathExpression. ';
|
||||||
|
$semanticalError .= (count($expectedStringTypes) == 1)
|
||||||
if (count($expectedStringTypes) == 1) {
|
? 'Must be a ' . $expectedStringTypes[0] . '.'
|
||||||
$semanticalError .= 'Must be a ' . $expectedStringTypes[0] . '.';
|
: implode(' or ', $expectedStringTypes) . ' expected.';
|
||||||
} else {
|
|
||||||
$semanticalError .= implode(' or ', $expectedStringTypes) . ' expected.';
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->semanticalError($semanticalError, $deferredItem['token']);
|
$this->semanticalError($semanticalError, $deferredItem['token']);
|
||||||
}
|
}
|
||||||
@ -1308,7 +1305,7 @@ class Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GroupByItem ::= IdentificationVariable | SingleValuedPathExpression
|
* GroupByItem ::= IdentificationVariable | ResultVariable | SingleValuedPathExpression
|
||||||
*
|
*
|
||||||
* @return string | \Doctrine\ORM\Query\AST\PathExpression
|
* @return string | \Doctrine\ORM\Query\AST\PathExpression
|
||||||
*/
|
*/
|
||||||
@ -1317,18 +1314,20 @@ class Parser
|
|||||||
// We need to check if we are in a IdentificationVariable or SingleValuedPathExpression
|
// We need to check if we are in a IdentificationVariable or SingleValuedPathExpression
|
||||||
$glimpse = $this->_lexer->glimpse();
|
$glimpse = $this->_lexer->glimpse();
|
||||||
|
|
||||||
if ($glimpse['type'] == Lexer::T_DOT) {
|
if ($glimpse['type'] === Lexer::T_DOT) {
|
||||||
return $this->SingleValuedPathExpression();
|
return $this->SingleValuedPathExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $this->_lexer->lookahead;
|
// Still need to decide between IdentificationVariable or ResultVariable
|
||||||
$identVariable = $this->IdentificationVariable();
|
$lookaheadValue = $this->_lexer->lookahead['value'];
|
||||||
|
|
||||||
if ( ! isset($this->_queryComponents[$identVariable])) {
|
if ( ! isset($this->_queryComponents[$lookaheadValue])) {
|
||||||
$this->semanticalError('Cannot group by undefined identification variable.');
|
$this->semanticalError('Cannot group by undefined identification or result variable.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $identVariable;
|
return (isset($this->_queryComponents[$lookaheadValue]['metadata']))
|
||||||
|
? $this->IdentificationVariable()
|
||||||
|
: $this->ResultVariable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1866,53 +1865,78 @@ class Parser
|
|||||||
$expression = null;
|
$expression = null;
|
||||||
$identVariable = null;
|
$identVariable = null;
|
||||||
$peek = $this->_lexer->glimpse();
|
$peek = $this->_lexer->glimpse();
|
||||||
|
$lookaheadType = $this->_lexer->lookahead['type'];
|
||||||
|
|
||||||
if ($this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER && $peek['type'] === Lexer::T_DOT) {
|
switch (true) {
|
||||||
// ScalarExpression (u.name)
|
// ScalarExpression (u.name)
|
||||||
$expression = $this->ScalarExpression();
|
case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] === Lexer::T_DOT):
|
||||||
} else if ($this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER && $peek['type'] !== Lexer::T_OPEN_PARENTHESIS) {
|
|
||||||
// IdentificationVariable (u)
|
|
||||||
$expression = $identVariable = $this->IdentificationVariable();
|
|
||||||
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_CASE, Lexer::T_COALESCE, Lexer::T_NULLIF))) {
|
|
||||||
// CaseExpression (CASE ... or NULLIF(...) or COALESCE(...))
|
|
||||||
$expression = $this->CaseExpression();
|
|
||||||
} else if ($this->_isFunction()) {
|
|
||||||
// DQL Function (SUM(u.value) or SUM(u.value) + 1)
|
|
||||||
$this->_lexer->peek(); // "("
|
|
||||||
|
|
||||||
$lookaheadType = $this->_lexer->lookahead['type'];
|
|
||||||
$beyond = $this->_peekBeyondClosingParenthesis();
|
|
||||||
|
|
||||||
if ($this->_isMathOperator($beyond)) {
|
|
||||||
// SUM(u.id) + COUNT(u.id)
|
|
||||||
$expression = $this->ScalarExpression();
|
$expression = $this->ScalarExpression();
|
||||||
} else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
|
break;
|
||||||
// COUNT(u.id)
|
|
||||||
$expression = $this->AggregateExpression();
|
// IdentificationVariable (u)
|
||||||
} else {
|
case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] !== Lexer::T_OPEN_PARENTHESIS):
|
||||||
// SUM(u.id)
|
$expression = $identVariable = $this->IdentificationVariable();
|
||||||
$expression = $this->FunctionDeclaration();
|
break;
|
||||||
}
|
|
||||||
} else if ($this->_lexer->lookahead['type'] === Lexer::T_PARTIAL) {
|
// CaseExpression (CASE ... or NULLIF(...) or COALESCE(...))
|
||||||
|
case ($lookaheadType === Lexer::T_CASE):
|
||||||
|
case ($lookaheadType === Lexer::T_COALESCE):
|
||||||
|
case ($lookaheadType === Lexer::T_NULLIF):
|
||||||
|
$expression = $this->CaseExpression();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// DQL Function (SUM(u.value) or SUM(u.value) + 1)
|
||||||
|
case ($this->_isFunction()):
|
||||||
|
$this->_lexer->peek(); // "("
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case ($this->_isMathOperator($this->_peekBeyondClosingParenthesis())):
|
||||||
|
// SUM(u.id) + COUNT(u.id)
|
||||||
|
$expression = $this->ScalarExpression();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ($this->_isAggregateFunction($lookaheadType)):
|
||||||
|
// COUNT(u.id)
|
||||||
|
$expression = $this->AggregateExpression();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// IDENTITY(u)
|
||||||
|
$expression = $this->FunctionDeclaration();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
// PartialObjectExpression (PARTIAL u.{id, name})
|
// PartialObjectExpression (PARTIAL u.{id, name})
|
||||||
$expression = $this->PartialObjectExpression();
|
case ($lookaheadType === Lexer::T_PARTIAL):
|
||||||
$identVariable = $expression->identificationVariable;
|
$expression = $this->PartialObjectExpression();
|
||||||
} else if ($this->_lexer->lookahead['type'] === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT) {
|
$identVariable = $expression->identificationVariable;
|
||||||
|
break;
|
||||||
|
|
||||||
// Subselect
|
// Subselect
|
||||||
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT):
|
||||||
$expression = $this->Subselect();
|
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
||||||
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
$expression = $this->Subselect();
|
||||||
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_OPEN_PARENTHESIS, Lexer::T_INTEGER, Lexer::T_FLOAT, Lexer::T_STRING))) {
|
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||||
|
break;
|
||||||
|
|
||||||
// Shortcut: ScalarExpression => SimpleArithmeticExpression
|
// Shortcut: ScalarExpression => SimpleArithmeticExpression
|
||||||
$expression = $this->SimpleArithmeticExpression();
|
case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS):
|
||||||
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_PLUS, Lexer::T_MINUS))) {
|
case ($lookaheadType === Lexer::T_INTEGER):
|
||||||
// SimpleArithmeticExpression : (- u.value ) or ( + u.value )
|
case ($lookaheadType === Lexer::T_STRING):
|
||||||
$expression = $this->SimpleArithmeticExpression();
|
case ($lookaheadType === Lexer::T_FLOAT):
|
||||||
} else {
|
// SimpleArithmeticExpression : (- u.value ) or ( + u.value )
|
||||||
$this->syntaxError(
|
case ($lookaheadType === Lexer::T_MINUS):
|
||||||
'IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression',
|
case ($lookaheadType === Lexer::T_PLUS):
|
||||||
$this->_lexer->lookahead
|
$expression = $this->SimpleArithmeticExpression();
|
||||||
);
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$this->syntaxError(
|
||||||
|
'IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression',
|
||||||
|
$this->_lexer->lookahead
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// [["AS"] ["HIDDEN"] AliasResultVariable]
|
// [["AS"] ["HIDDEN"] AliasResultVariable]
|
||||||
@ -1965,25 +1989,41 @@ class Parser
|
|||||||
{
|
{
|
||||||
$peek = $this->_lexer->glimpse();
|
$peek = $this->_lexer->glimpse();
|
||||||
|
|
||||||
if ($peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) {
|
switch ($this->_lexer->lookahead['type']) {
|
||||||
// SingleValuedPathExpression | IdentificationVariable
|
case Lexer::T_IDENTIFIER:
|
||||||
$expression = ($peek['value'] == '.')
|
switch (true) {
|
||||||
? $this->StateFieldPathExpression()
|
case ($peek['type'] === Lexer::T_DOT):
|
||||||
: $this->IdentificationVariable();
|
$expression = $this->StateFieldPathExpression();
|
||||||
|
|
||||||
|
return new AST\SimpleSelectExpression($expression);
|
||||||
|
|
||||||
|
case ($peek['type'] !== Lexer::T_OPEN_PARENTHESIS):
|
||||||
|
$expression = $this->IdentificationVariable();
|
||||||
|
|
||||||
|
return new AST\SimpleSelectExpression($expression);
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Lexer::T_OPEN_PARENTHESIS:
|
||||||
|
if ($peek['type'] !== Lexer::T_SELECT) {
|
||||||
|
// Shortcut: ScalarExpression => SimpleArithmeticExpression
|
||||||
|
$expression = $this->SimpleArithmeticExpression();
|
||||||
|
|
||||||
|
return new AST\SimpleSelectExpression($expression);
|
||||||
|
}
|
||||||
|
|
||||||
return new AST\SimpleSelectExpression($expression);
|
|
||||||
} else if ($this->_lexer->lookahead['value'] == '(') {
|
|
||||||
if ($peek['type'] == Lexer::T_SELECT) {
|
|
||||||
// Subselect
|
// Subselect
|
||||||
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
||||||
$expression = $this->Subselect();
|
$expression = $this->Subselect();
|
||||||
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||||
} else {
|
|
||||||
// Shortcut: ScalarExpression => SimpleArithmeticExpression
|
|
||||||
$expression = $this->SimpleArithmeticExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AST\SimpleSelectExpression($expression);
|
return new AST\SimpleSelectExpression($expression);
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_lexer->peek();
|
$this->_lexer->peek();
|
||||||
@ -2099,27 +2139,26 @@ class Parser
|
|||||||
{
|
{
|
||||||
$condPrimary = new AST\ConditionalPrimary;
|
$condPrimary = new AST\ConditionalPrimary;
|
||||||
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
|
if ( ! $this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
|
||||||
// Peek beyond the matching closing paranthesis ')'
|
|
||||||
$peek = $this->_peekBeyondClosingParenthesis();
|
|
||||||
|
|
||||||
if (in_array($peek['value'], array("=", "<", "<=", "<>", ">", ">=", "!=")) ||
|
|
||||||
$peek['type'] === Lexer::T_NOT ||
|
|
||||||
$peek['type'] === Lexer::T_BETWEEN ||
|
|
||||||
$peek['type'] === Lexer::T_LIKE ||
|
|
||||||
$peek['type'] === Lexer::T_IN ||
|
|
||||||
$peek['type'] === Lexer::T_IS ||
|
|
||||||
$peek['type'] === Lexer::T_EXISTS) {
|
|
||||||
$condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
|
|
||||||
} else {
|
|
||||||
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
|
||||||
$condPrimary->conditionalExpression = $this->ConditionalExpression();
|
|
||||||
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
|
$condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
|
||||||
|
|
||||||
|
return $condPrimary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Peek beyond the matching closing paranthesis ')'
|
||||||
|
$peek = $this->_peekBeyondClosingParenthesis();
|
||||||
|
|
||||||
|
if (in_array($peek['value'], array("=", "<", "<=", "<>", ">", ">=", "!=")) ||
|
||||||
|
in_array($peek['type'], array(Lexer::T_NOT, Lexer::T_BETWEEN, Lexer::T_LIKE, Lexer::T_IN, Lexer::T_IS, Lexer::T_EXISTS))) {
|
||||||
|
$condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
|
||||||
|
|
||||||
|
return $condPrimary;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
||||||
|
$condPrimary->conditionalExpression = $this->ConditionalExpression();
|
||||||
|
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||||
|
|
||||||
return $condPrimary;
|
return $condPrimary;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2132,10 +2171,10 @@ class Parser
|
|||||||
*/
|
*/
|
||||||
public function SimpleConditionalExpression()
|
public function SimpleConditionalExpression()
|
||||||
{
|
{
|
||||||
|
$token = $this->_lexer->lookahead;
|
||||||
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
|
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
|
||||||
$token = $this->_lexer->glimpse();
|
$token = $this->_lexer->glimpse();
|
||||||
} else {
|
|
||||||
$token = $this->_lexer->lookahead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($token['type'] === Lexer::T_EXISTS) {
|
if ($token['type'] === Lexer::T_EXISTS) {
|
||||||
@ -2464,9 +2503,9 @@ class Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $this->FunctionDeclaration();
|
return $this->FunctionDeclaration();
|
||||||
} else {
|
|
||||||
return $this->Literal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->Literal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2498,30 +2537,46 @@ class Parser
|
|||||||
*/
|
*/
|
||||||
public function StringPrimary()
|
public function StringPrimary()
|
||||||
{
|
{
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
$lookaheadType = $this->_lexer->lookahead['type'];
|
||||||
$peek = $this->_lexer->glimpse();
|
|
||||||
|
switch ($lookaheadType) {
|
||||||
|
case Lexer::T_IDENTIFIER:
|
||||||
|
$peek = $this->_lexer->glimpse();
|
||||||
|
|
||||||
|
if ($peek['value'] == '.') {
|
||||||
|
return $this->StateFieldPathExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($peek['value'] == '(') {
|
||||||
|
// do NOT directly go to FunctionsReturningString() because it doesnt check for custom functions.
|
||||||
|
return $this->FunctionDeclaration();
|
||||||
|
}
|
||||||
|
|
||||||
if ($peek['value'] == '.') {
|
|
||||||
return $this->StateFieldPathExpression();
|
|
||||||
} else if ($peek['value'] == '(') {
|
|
||||||
// do NOT directly go to FunctionsReturningString() because it doesnt check for custom functions.
|
|
||||||
return $this->FunctionDeclaration();
|
|
||||||
} else {
|
|
||||||
$this->syntaxError("'.' or '('");
|
$this->syntaxError("'.' or '('");
|
||||||
}
|
break;
|
||||||
} else if ($this->_lexer->isNextToken(Lexer::T_STRING)) {
|
|
||||||
$this->match(Lexer::T_STRING);
|
|
||||||
|
|
||||||
return $this->_lexer->token['value'];
|
case Lexer::T_STRING:
|
||||||
} else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
|
$this->match(Lexer::T_STRING);
|
||||||
return $this->InputParameter();
|
|
||||||
} else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
|
return $this->_lexer->token['value'];
|
||||||
return $this->AggregateExpression();
|
|
||||||
} else if (in_array($this->_lexer->lookahead['type'], array(Lexer::T_CASE, Lexer::T_COALESCE, Lexer::T_NULLIF))) {
|
case Lexer::T_INPUT_PARAMETER:
|
||||||
return $this->CaseExpression();
|
return $this->InputParameter();
|
||||||
|
|
||||||
|
case Lexer::T_CASE:
|
||||||
|
case Lexer::T_COALESCE:
|
||||||
|
case Lexer::T_NULLIF:
|
||||||
|
return $this->CaseExpression();
|
||||||
|
|
||||||
|
default:
|
||||||
|
if ($this->_isAggregateFunction($lookaheadType)) {
|
||||||
|
return $this->AggregateExpression();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->syntaxError('StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression');
|
$this->syntaxError(
|
||||||
|
'StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2552,7 +2607,7 @@ class Parser
|
|||||||
return $this->InputParameter();
|
return $this->InputParameter();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->IdentificationVariable();
|
return $this->StateFieldPathExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2564,40 +2619,28 @@ class Parser
|
|||||||
*/
|
*/
|
||||||
public function AggregateExpression()
|
public function AggregateExpression()
|
||||||
{
|
{
|
||||||
|
$lookaheadType = $this->_lexer->lookahead['type'];
|
||||||
$isDistinct = false;
|
$isDistinct = false;
|
||||||
$functionName = '';
|
|
||||||
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_COUNT)) {
|
if ( ! in_array($lookaheadType, array(Lexer::T_COUNT, Lexer::T_AVG, Lexer::T_MAX, Lexer::T_MIN, Lexer::T_SUM))) {
|
||||||
$this->match(Lexer::T_COUNT);
|
$this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT');
|
||||||
$functionName = $this->_lexer->token['value'];
|
|
||||||
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
|
||||||
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
|
|
||||||
$this->match(Lexer::T_DISTINCT);
|
|
||||||
$isDistinct = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$pathExp = $this->SingleValuedPathExpression();
|
|
||||||
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
|
||||||
} else {
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_AVG)) {
|
|
||||||
$this->match(Lexer::T_AVG);
|
|
||||||
} else if ($this->_lexer->isNextToken(Lexer::T_MAX)) {
|
|
||||||
$this->match(Lexer::T_MAX);
|
|
||||||
} else if ($this->_lexer->isNextToken(Lexer::T_MIN)) {
|
|
||||||
$this->match(Lexer::T_MIN);
|
|
||||||
} else if ($this->_lexer->isNextToken(Lexer::T_SUM)) {
|
|
||||||
$this->match(Lexer::T_SUM);
|
|
||||||
} else {
|
|
||||||
$this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT');
|
|
||||||
}
|
|
||||||
|
|
||||||
$functionName = $this->_lexer->token['value'];
|
|
||||||
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
|
||||||
$pathExp = $this->SimpleArithmeticExpression();
|
|
||||||
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->match($lookaheadType);
|
||||||
|
$functionName = $this->_lexer->token['value'];
|
||||||
|
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
||||||
|
|
||||||
|
if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
|
||||||
|
$this->match(Lexer::T_DISTINCT);
|
||||||
|
$isDistinct = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pathExp = ($lookaheadType === Lexer::T_COUNT)
|
||||||
|
? $this->SingleValuedPathExpression()
|
||||||
|
: $this->SimpleArithmeticExpression();
|
||||||
|
|
||||||
|
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||||
|
|
||||||
return new AST\AggregateExpression($functionName, $pathExp, $isDistinct);
|
return new AST\AggregateExpression($functionName, $pathExp, $isDistinct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2608,24 +2651,19 @@ class Parser
|
|||||||
*/
|
*/
|
||||||
public function QuantifiedExpression()
|
public function QuantifiedExpression()
|
||||||
{
|
{
|
||||||
$type = '';
|
$lookaheadType = $this->_lexer->lookahead['type'];
|
||||||
|
$value = $this->_lexer->lookahead['value'];
|
||||||
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_ALL)) {
|
if ( ! in_array($lookaheadType, array(Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME))) {
|
||||||
$this->match(Lexer::T_ALL);
|
|
||||||
$type = 'ALL';
|
|
||||||
} else if ($this->_lexer->isNextToken(Lexer::T_ANY)) {
|
|
||||||
$this->match(Lexer::T_ANY);
|
|
||||||
$type = 'ANY';
|
|
||||||
} else if ($this->_lexer->isNextToken(Lexer::T_SOME)) {
|
|
||||||
$this->match(Lexer::T_SOME);
|
|
||||||
$type = 'SOME';
|
|
||||||
} else {
|
|
||||||
$this->syntaxError('ALL, ANY or SOME');
|
$this->syntaxError('ALL, ANY or SOME');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->match($lookaheadType);
|
||||||
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
||||||
|
|
||||||
$qExpr = new AST\QuantifiedExpression($this->Subselect());
|
$qExpr = new AST\QuantifiedExpression($this->Subselect());
|
||||||
$qExpr->type = $type;
|
$qExpr->type = $value;
|
||||||
|
|
||||||
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||||
|
|
||||||
return $qExpr;
|
return $qExpr;
|
||||||
@ -2666,14 +2704,11 @@ class Parser
|
|||||||
{
|
{
|
||||||
$peek = $this->_lexer->glimpse();
|
$peek = $this->_lexer->glimpse();
|
||||||
|
|
||||||
$leftExpr = $this->ArithmeticExpression();
|
$leftExpr = $this->ArithmeticExpression();
|
||||||
$operator = $this->ComparisonOperator();
|
$operator = $this->ComparisonOperator();
|
||||||
|
$rightExpr = ($this->_isNextAllAnySome())
|
||||||
if ($this->_isNextAllAnySome()) {
|
? $this->QuantifiedExpression()
|
||||||
$rightExpr = $this->QuantifiedExpression();
|
: $this->ArithmeticExpression();
|
||||||
} else {
|
|
||||||
$rightExpr = $this->ArithmeticExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr);
|
return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr);
|
||||||
}
|
}
|
||||||
@ -2685,7 +2720,7 @@ class Parser
|
|||||||
*/
|
*/
|
||||||
public function InExpression()
|
public function InExpression()
|
||||||
{
|
{
|
||||||
$inExpression = new AST\InExpression($this->SingleValuedPathExpression());
|
$inExpression = new AST\InExpression($this->ArithmeticExpression());
|
||||||
|
|
||||||
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
|
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
|
||||||
$this->match(Lexer::T_NOT);
|
$this->match(Lexer::T_NOT);
|
||||||
|
@ -435,7 +435,8 @@ class SqlWalker implements TreeWalker
|
|||||||
{
|
{
|
||||||
$this->_useSqlTableAliases = false;
|
$this->_useSqlTableAliases = false;
|
||||||
|
|
||||||
return $this->walkUpdateClause($AST->updateClause) . $this->walkWhereClause($AST->whereClause);
|
return $this->walkUpdateClause($AST->updateClause)
|
||||||
|
. $this->walkWhereClause($AST->whereClause);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -448,9 +449,29 @@ class SqlWalker implements TreeWalker
|
|||||||
{
|
{
|
||||||
$this->_useSqlTableAliases = false;
|
$this->_useSqlTableAliases = false;
|
||||||
|
|
||||||
return $this->walkDeleteClause($AST->deleteClause) . $this->walkWhereClause($AST->whereClause);
|
return $this->walkDeleteClause($AST->deleteClause)
|
||||||
|
. $this->walkWhereClause($AST->whereClause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walks down an IdentificationVariable AST node, thereby generating the appropriate SQL.
|
||||||
|
* This one differs of ->walkIdentificationVariable() because it generates the entity identifiers.
|
||||||
|
*
|
||||||
|
* @param string $identVariable
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function walkEntityIdentificationVariable($identVariable)
|
||||||
|
{
|
||||||
|
$class = $this->_queryComponents[$identVariable]['metadata'];
|
||||||
|
$tableAlias = $this->getSQLTableAlias($class->getTableName(), $identVariable);
|
||||||
|
$sqlParts = array();
|
||||||
|
|
||||||
|
foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
|
||||||
|
$sqlParts[] = $tableAlias . '.' . $columnName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(', ', $sqlParts);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks down an IdentificationVariable (no AST node associated), thereby generating the SQL.
|
* Walks down an IdentificationVariable (no AST node associated), thereby generating the SQL.
|
||||||
@ -713,7 +734,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$expr = $orderByItem->expression;
|
$expr = $orderByItem->expression;
|
||||||
$sql = ($expr instanceof AST\PathExpression)
|
$sql = ($expr instanceof AST\PathExpression)
|
||||||
? $this->walkPathExpression($expr)
|
? $this->walkPathExpression($expr)
|
||||||
: $this->_scalarResultAliasMap[$this->_queryComponents[$expr]['token']['value']];
|
: $this->walkResultVariable($this->_queryComponents[$expr]['token']['value']);
|
||||||
|
|
||||||
return $sql . ' ' . strtoupper($orderByItem->type);
|
return $sql . ' ' . strtoupper($orderByItem->type);
|
||||||
}
|
}
|
||||||
@ -1050,6 +1071,8 @@ class SqlWalker implements TreeWalker
|
|||||||
|
|
||||||
$sql .= $col . ' AS ' . $columnAlias;
|
$sql .= $col . ' AS ' . $columnAlias;
|
||||||
|
|
||||||
|
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
|
||||||
|
|
||||||
if ( ! $hidden) {
|
if ( ! $hidden) {
|
||||||
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
|
||||||
$this->_scalarFields[$dqlAlias][$fieldName] = $columnAlias;
|
$this->_scalarFields[$dqlAlias][$fieldName] = $columnAlias;
|
||||||
@ -1139,6 +1162,8 @@ class SqlWalker implements TreeWalker
|
|||||||
|
|
||||||
$sqlParts[] = $col . ' AS '. $columnAlias;
|
$sqlParts[] = $col . ' AS '. $columnAlias;
|
||||||
|
|
||||||
|
$this->_scalarResultAliasMap[$resultAlias][] = $columnAlias;
|
||||||
|
|
||||||
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name);
|
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1168,6 +1193,8 @@ class SqlWalker implements TreeWalker
|
|||||||
|
|
||||||
$sqlParts[] = $col . ' AS ' . $columnAlias;
|
$sqlParts[] = $col . ' AS ' . $columnAlias;
|
||||||
|
|
||||||
|
$this->_scalarResultAliasMap[$resultAlias][] = $columnAlias;
|
||||||
|
|
||||||
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName);
|
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1317,15 +1344,7 @@ class SqlWalker implements TreeWalker
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default: // IdentificationVariable
|
default: // IdentificationVariable
|
||||||
$class = $this->_queryComponents[$expr]['metadata'];
|
$sql .= $this->walkEntityIdentificationVariable($expr);
|
||||||
$tableAlias = $this->getSQLTableAlias($class->getTableName(), $expr);
|
|
||||||
$sqlParts = array();
|
|
||||||
|
|
||||||
foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
|
|
||||||
$sqlParts[] = $tableAlias . '.' . $columnName;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= implode(', ', $sqlParts);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1355,25 +1374,7 @@ class SqlWalker implements TreeWalker
|
|||||||
$sqlParts = array();
|
$sqlParts = array();
|
||||||
|
|
||||||
foreach ($groupByClause->groupByItems AS $groupByItem) {
|
foreach ($groupByClause->groupByItems AS $groupByItem) {
|
||||||
if ( ! is_string($groupByItem)) {
|
$sqlParts[] = $this->walkGroupByItem($groupByItem);
|
||||||
$sqlParts[] = $this->walkGroupByItem($groupByItem);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->_queryComponents[$groupByItem]['metadata']->fieldNames AS $field) {
|
|
||||||
$item = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $field);
|
|
||||||
$item->type = AST\PathExpression::TYPE_STATE_FIELD;
|
|
||||||
$sqlParts[] = $this->walkGroupByItem($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->_queryComponents[$groupByItem]['metadata']->associationMappings AS $mapping) {
|
|
||||||
if ($mapping['isOwningSide'] && $mapping['type'] & ClassMetadataInfo::TO_ONE) {
|
|
||||||
$item = new AST\PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $groupByItem, $mapping['fieldName']);
|
|
||||||
$item->type = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION;
|
|
||||||
$sqlParts[] = $this->walkGroupByItem($item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ' GROUP BY ' . implode(', ', $sqlParts);
|
return ' GROUP BY ' . implode(', ', $sqlParts);
|
||||||
@ -1385,9 +1386,38 @@ class SqlWalker implements TreeWalker
|
|||||||
* @param GroupByItem
|
* @param GroupByItem
|
||||||
* @return string The SQL.
|
* @return string The SQL.
|
||||||
*/
|
*/
|
||||||
public function walkGroupByItem(AST\PathExpression $pathExpr)
|
public function walkGroupByItem($groupByItem)
|
||||||
{
|
{
|
||||||
return $this->walkPathExpression($pathExpr);
|
// StateFieldPathExpression
|
||||||
|
if ( ! is_string($groupByItem)) {
|
||||||
|
return $this->walkPathExpression($groupByItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultVariable
|
||||||
|
if (isset($this->_queryComponents[$groupByItem]['resultVariable'])) {
|
||||||
|
return $this->walkResultVariable($groupByItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IdentificationVariable
|
||||||
|
$sqlParts = array();
|
||||||
|
|
||||||
|
foreach ($this->_queryComponents[$groupByItem]['metadata']->fieldNames AS $field) {
|
||||||
|
$item = new AST\PathExpression(AST\PathExpression::TYPE_STATE_FIELD, $groupByItem, $field);
|
||||||
|
$item->type = AST\PathExpression::TYPE_STATE_FIELD;
|
||||||
|
|
||||||
|
$sqlParts[] = $this->walkPathExpression($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->_queryComponents[$groupByItem]['metadata']->associationMappings AS $mapping) {
|
||||||
|
if ($mapping['isOwningSide'] && $mapping['type'] & ClassMetadataInfo::TO_ONE) {
|
||||||
|
$item = new AST\PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $groupByItem, $mapping['fieldName']);
|
||||||
|
$item->type = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION;
|
||||||
|
|
||||||
|
$sqlParts[] = $this->walkPathExpression($item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(', ', $sqlParts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1597,20 +1627,30 @@ class SqlWalker implements TreeWalker
|
|||||||
{
|
{
|
||||||
$sql = $collMemberExpr->not ? 'NOT ' : '';
|
$sql = $collMemberExpr->not ? 'NOT ' : '';
|
||||||
$sql .= 'EXISTS (SELECT 1 FROM ';
|
$sql .= 'EXISTS (SELECT 1 FROM ';
|
||||||
$entityExpr = $collMemberExpr->entityExpression;
|
|
||||||
|
$entityExpr = $collMemberExpr->entityExpression;
|
||||||
$collPathExpr = $collMemberExpr->collectionValuedPathExpression;
|
$collPathExpr = $collMemberExpr->collectionValuedPathExpression;
|
||||||
|
|
||||||
$fieldName = $collPathExpr->field;
|
$fieldName = $collPathExpr->field;
|
||||||
$dqlAlias = $collPathExpr->identificationVariable;
|
$dqlAlias = $collPathExpr->identificationVariable;
|
||||||
|
|
||||||
$class = $this->_queryComponents[$dqlAlias]['metadata'];
|
$class = $this->_queryComponents[$dqlAlias]['metadata'];
|
||||||
|
|
||||||
if ($entityExpr instanceof AST\InputParameter) {
|
switch (true) {
|
||||||
$dqlParamKey = $entityExpr->name;
|
// InputParameter
|
||||||
$entity = $this->_query->getParameter($dqlParamKey);
|
case ($entityExpr instanceof AST\InputParameter):
|
||||||
} else {
|
$dqlParamKey = $entityExpr->name;
|
||||||
//TODO
|
$entity = $this->_query->getParameter($dqlParamKey);
|
||||||
throw new \BadMethodCallException("Not implemented");
|
$entitySql = '?';
|
||||||
|
break;
|
||||||
|
|
||||||
|
// SingleValuedAssociationPathExpression | IdentificationVariable
|
||||||
|
case ($entityExpr instanceof AST\PathExpression):
|
||||||
|
$entitySql = $this->walkPathExpression($entityExpr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \BadMethodCallException("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
$assoc = $class->associationMappings[$fieldName];
|
$assoc = $class->associationMappings[$fieldName];
|
||||||
@ -1623,25 +1663,23 @@ class SqlWalker implements TreeWalker
|
|||||||
$sql .= $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' WHERE ';
|
$sql .= $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' WHERE ';
|
||||||
|
|
||||||
$owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']];
|
$owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']];
|
||||||
$first = true;
|
$sqlParts = array();
|
||||||
|
|
||||||
foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) {
|
foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) {
|
||||||
if ($first) $first = false; else $sql .= ' AND ';
|
$targetColumn = $class->getQuotedColumnName($class->fieldNames[$targetColumn], $this->_platform);
|
||||||
|
|
||||||
$sql .= $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$targetColumn], $this->_platform)
|
$sqlParts[] = $sourceTableAlias . '.' . $targetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn;
|
||||||
. ' = '
|
|
||||||
. $targetTableAlias . '.' . $sourceColumn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql .= ' AND ';
|
|
||||||
$first = true;
|
|
||||||
|
|
||||||
foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) {
|
foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) {
|
||||||
if ($first) $first = false; else $sql .= ' AND ';
|
if (isset($dqlParamKey)) {
|
||||||
|
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
|
||||||
|
}
|
||||||
|
|
||||||
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
|
$sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql;
|
||||||
$sql .= $targetTableAlias . '.' . $targetColumnName . ' = ?';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sql .= implode(' AND ', $sqlParts);
|
||||||
} else { // many-to-many
|
} else { // many-to-many
|
||||||
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
|
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
|
||||||
|
|
||||||
@ -1658,39 +1696,42 @@ class SqlWalker implements TreeWalker
|
|||||||
. ' INNER JOIN ' . $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' ON ';
|
. ' INNER JOIN ' . $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' ON ';
|
||||||
|
|
||||||
// join conditions
|
// join conditions
|
||||||
$joinColumns = $assoc['isOwningSide']
|
$joinColumns = $assoc['isOwningSide'] ? $joinTable['inverseJoinColumns'] : $joinTable['joinColumns'];
|
||||||
? $joinTable['inverseJoinColumns']
|
$joinSqlParts = array();
|
||||||
: $joinTable['joinColumns'];
|
|
||||||
|
|
||||||
$first = true;
|
|
||||||
foreach ($joinColumns as $joinColumn) {
|
foreach ($joinColumns as $joinColumn) {
|
||||||
if ($first) $first = false; else $sql .= ' AND ';
|
$targetColumn = $targetClass->getQuotedColumnName(
|
||||||
|
$targetClass->fieldNames[$joinColumn['referencedColumnName']],
|
||||||
|
$this->_platform
|
||||||
|
);
|
||||||
|
|
||||||
$sql .= $joinTableAlias . '.' . $joinColumn['name'] . ' = '
|
$joinSqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $targetTableAlias . '.' . $targetColumn;
|
||||||
. $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->fieldNames[$joinColumn['referencedColumnName']], $this->_platform);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sql .= implode(' AND ', $joinSqlParts);
|
||||||
$sql .= ' WHERE ';
|
$sql .= ' WHERE ';
|
||||||
|
|
||||||
$joinColumns = $assoc['isOwningSide'] ? $joinTable['joinColumns'] : $joinTable['inverseJoinColumns'];
|
$joinColumns = $assoc['isOwningSide'] ? $joinTable['joinColumns'] : $joinTable['inverseJoinColumns'];
|
||||||
$first = true;
|
$sqlParts = array();
|
||||||
|
|
||||||
foreach ($joinColumns as $joinColumn) {
|
foreach ($joinColumns as $joinColumn) {
|
||||||
if ($first) $first = false; else $sql .= ' AND ';
|
$targetColumn = $class->getQuotedColumnName(
|
||||||
|
$class->fieldNames[$joinColumn['referencedColumnName']],
|
||||||
|
$this->_platform
|
||||||
|
);
|
||||||
|
|
||||||
$sql .= $joinTableAlias . '.' . $joinColumn['name'] . ' = '
|
$sqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $sourceTableAlias . '.' . $targetColumn;
|
||||||
. $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$joinColumn['referencedColumnName']], $this->_platform);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql .= ' AND ';
|
|
||||||
$first = true;
|
|
||||||
|
|
||||||
foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) {
|
foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) {
|
||||||
if ($first) $first = false; else $sql .= ' AND ';
|
if (isset($dqlParamKey)) {
|
||||||
|
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
|
||||||
|
}
|
||||||
|
|
||||||
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
|
$sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql;
|
||||||
$sql .= $targetTableAlias . '.' . $targetColumnName . ' = ?';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sql .= implode(' AND ', $sqlParts);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sql . ')';
|
return $sql . ')';
|
||||||
@ -1742,8 +1783,7 @@ class SqlWalker implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function walkInExpression($inExpr)
|
public function walkInExpression($inExpr)
|
||||||
{
|
{
|
||||||
$sql = $this->walkPathExpression($inExpr->pathExpression)
|
$sql = $this->walkArithmeticExpression($inExpr->expression) . ($inExpr->not ? ' NOT' : '') . ' IN (';
|
||||||
. ($inExpr->not ? ' NOT' : '') . ' IN (';
|
|
||||||
|
|
||||||
$sql .= ($inExpr->subselect)
|
$sql .= ($inExpr->subselect)
|
||||||
? $this->walkSubselect($inExpr->subselect)
|
? $this->walkSubselect($inExpr->subselect)
|
||||||
@ -1985,7 +2025,7 @@ class SqlWalker implements TreeWalker
|
|||||||
{
|
{
|
||||||
if (is_string($term)) {
|
if (is_string($term)) {
|
||||||
return (isset($this->_queryComponents[$term]))
|
return (isset($this->_queryComponents[$term]))
|
||||||
? $this->_scalarResultAliasMap[$this->_queryComponents[$term]['token']['value']]
|
? $this->walkResultVariable($this->_queryComponents[$term]['token']['value'])
|
||||||
: $term;
|
: $term;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2037,8 +2077,7 @@ class SqlWalker implements TreeWalker
|
|||||||
return $primary->dispatch($this);
|
return $primary->dispatch($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We need to deal with IdentificationVariable here
|
return $this->walkEntityIdentificationVariable($primary);
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2053,4 +2092,21 @@ class SqlWalker implements TreeWalker
|
|||||||
? $this->_conn->quote($stringPrimary)
|
? $this->_conn->quote($stringPrimary)
|
||||||
: $stringPrimary->dispatch($this);
|
: $stringPrimary->dispatch($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walks down a ResultVriable that represents an AST node, thereby generating the appropriate SQL.
|
||||||
|
*
|
||||||
|
* @param string $resultVariable
|
||||||
|
* @return string The SQL.
|
||||||
|
*/
|
||||||
|
public function walkResultVariable($resultVariable)
|
||||||
|
{
|
||||||
|
$resultAlias = $this->_scalarResultAliasMap[$resultVariable];
|
||||||
|
|
||||||
|
if (is_array($resultAlias)) {
|
||||||
|
return implode(', ', $resultAlias);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $resultAlias;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ interface TreeWalker
|
|||||||
* @param GroupByItem
|
* @param GroupByItem
|
||||||
* @return string The SQL.
|
* @return string The SQL.
|
||||||
*/
|
*/
|
||||||
function walkGroupByItem(AST\PathExpression $pathExpr);
|
function walkGroupByItem($groupByItem);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks down an UpdateStatement AST node, thereby generating the appropriate SQL.
|
* Walks down an UpdateStatement AST node, thereby generating the appropriate SQL.
|
||||||
@ -394,6 +394,14 @@ interface TreeWalker
|
|||||||
*/
|
*/
|
||||||
function walkPathExpression($pathExpr);
|
function walkPathExpression($pathExpr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walks down an ResultVariable AST node, thereby generating the appropriate SQL.
|
||||||
|
*
|
||||||
|
* @param string $resultVariable
|
||||||
|
* @return string The SQL.
|
||||||
|
*/
|
||||||
|
function walkResultVariable($resultVariable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an executor that can be used to execute the result of this walker.
|
* Gets an executor that can be used to execute the result of this walker.
|
||||||
*
|
*
|
||||||
|
@ -202,7 +202,7 @@ abstract class TreeWalkerAdapter implements TreeWalker
|
|||||||
* @param GroupByItem
|
* @param GroupByItem
|
||||||
* @return string The SQL.
|
* @return string The SQL.
|
||||||
*/
|
*/
|
||||||
public function walkGroupByItem(AST\PathExpression $pathExpr) {}
|
public function walkGroupByItem($groupByItem) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks down an UpdateStatement AST node, thereby generating the appropriate SQL.
|
* Walks down an UpdateStatement AST node, thereby generating the appropriate SQL.
|
||||||
@ -428,6 +428,14 @@ abstract class TreeWalkerAdapter implements TreeWalker
|
|||||||
*/
|
*/
|
||||||
public function walkPathExpression($pathExpr) {}
|
public function walkPathExpression($pathExpr) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walks down an ResultVariable AST node, thereby generating the appropriate SQL.
|
||||||
|
*
|
||||||
|
* @param string $resultVariable
|
||||||
|
* @return string The SQL.
|
||||||
|
*/
|
||||||
|
public function walkResultVariable($resultVariable) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an executor that can be used to execute the result of this walker.
|
* Gets an executor that can be used to execute the result of this walker.
|
||||||
*
|
*
|
||||||
|
@ -270,10 +270,10 @@ class TreeWalkerChain implements TreeWalker
|
|||||||
* @param GroupByItem
|
* @param GroupByItem
|
||||||
* @return string The SQL.
|
* @return string The SQL.
|
||||||
*/
|
*/
|
||||||
public function walkGroupByItem(AST\PathExpression $pathExpr)
|
public function walkGroupByItem($groupByItem)
|
||||||
{
|
{
|
||||||
foreach ($this->_walkers as $walker) {
|
foreach ($this->_walkers as $walker) {
|
||||||
$walker->walkGroupByItem($pathExpr);
|
$walker->walkGroupByItem($groupByItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,6 +641,19 @@ class TreeWalkerChain implements TreeWalker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walks down an ResultVariable AST node, thereby generating the appropriate SQL.
|
||||||
|
*
|
||||||
|
* @param string $resultVariable
|
||||||
|
* @return string The SQL.
|
||||||
|
*/
|
||||||
|
public function walkResultVariable($resultVariable)
|
||||||
|
{
|
||||||
|
foreach ($this->_walkers as $walker) {
|
||||||
|
$walker->walkResultVariable($resultVariable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an executor that can be used to execute the result of this walker.
|
* Gets an executor that can be used to execute the result of this walker.
|
||||||
*
|
*
|
||||||
|
@ -355,12 +355,9 @@ class QueryBuilder
|
|||||||
public function setParameters(array $params, array $types = array())
|
public function setParameters(array $params, array $types = array())
|
||||||
{
|
{
|
||||||
foreach ($params as $key => $value) {
|
foreach ($params as $key => $value) {
|
||||||
if (isset($types[$key])) {
|
$this->setParameter($key, $value, isset($types[$key]) ? $types[$key] : null);
|
||||||
$this->setParameter($key, $value, $types[$key]);
|
|
||||||
} else {
|
|
||||||
$this->setParameter($key, $value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,6 +391,7 @@ class QueryBuilder
|
|||||||
public function setFirstResult($firstResult)
|
public function setFirstResult($firstResult)
|
||||||
{
|
{
|
||||||
$this->_firstResult = $firstResult;
|
$this->_firstResult = $firstResult;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,6 +415,7 @@ class QueryBuilder
|
|||||||
public function setMaxResults($maxResults)
|
public function setMaxResults($maxResults)
|
||||||
{
|
{
|
||||||
$this->_maxResults = $maxResults;
|
$this->_maxResults = $maxResults;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,13 +651,16 @@ class QueryBuilder
|
|||||||
public function innerJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
|
public function innerJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
|
||||||
{
|
{
|
||||||
$rootAlias = substr($join, 0, strpos($join, '.'));
|
$rootAlias = substr($join, 0, strpos($join, '.'));
|
||||||
if (!in_array($rootAlias, $this->getRootAliases())) {
|
|
||||||
|
if ( ! in_array($rootAlias, $this->getRootAliases())) {
|
||||||
$rootAlias = $this->getRootAlias();
|
$rootAlias = $this->getRootAlias();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->add('join', array(
|
$join = new Expr\Join(
|
||||||
$rootAlias => new Expr\Join(Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition, $indexBy)
|
Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition, $indexBy
|
||||||
), true);
|
);
|
||||||
|
|
||||||
|
return $this->add('join', array($rootAlias => $join), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -685,13 +687,16 @@ class QueryBuilder
|
|||||||
public function leftJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
|
public function leftJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
|
||||||
{
|
{
|
||||||
$rootAlias = substr($join, 0, strpos($join, '.'));
|
$rootAlias = substr($join, 0, strpos($join, '.'));
|
||||||
if (!in_array($rootAlias, $this->getRootAliases())) {
|
|
||||||
|
if ( ! in_array($rootAlias, $this->getRootAliases())) {
|
||||||
$rootAlias = $this->getRootAlias();
|
$rootAlias = $this->getRootAlias();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->add('join', array(
|
$join = new Expr\Join(
|
||||||
$rootAlias => new Expr\Join(Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition, $indexBy)
|
Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition, $indexBy
|
||||||
), true);
|
);
|
||||||
|
|
||||||
|
return $this->add('join', array($rootAlias => $join), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,7 +196,7 @@ public function <methodName>()
|
|||||||
if ($this->_backupExisting && file_exists($path)) {
|
if ($this->_backupExisting && file_exists($path)) {
|
||||||
$backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . "~";
|
$backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . "~";
|
||||||
if (!copy($path, $backupPath)) {
|
if (!copy($path, $backupPath)) {
|
||||||
throw new \RuntimeException("Attempt to backup overwritten entitiy file but copy operation failed.");
|
throw new \RuntimeException("Attempt to backup overwritten entity file but copy operation failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -754,7 +754,7 @@ public function <methodName>()
|
|||||||
'<variableName>' => Inflector::camelize($fieldName),
|
'<variableName>' => Inflector::camelize($fieldName),
|
||||||
'<methodName>' => $methodName,
|
'<methodName>' => $methodName,
|
||||||
'<fieldName>' => $fieldName,
|
'<fieldName>' => $fieldName,
|
||||||
'<variableDefault>' => ($defaultValue !== null ) ? ('='.$defaultValue) : '',
|
'<variableDefault>' => ($defaultValue !== null ) ? (' = '.$defaultValue) : '',
|
||||||
'<entity>' => $this->_getClassName($metadata)
|
'<entity>' => $this->_getClassName($metadata)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1700,21 +1700,18 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
// do not merge fields marked lazy that have not been fetched.
|
// do not merge fields marked lazy that have not been fetched.
|
||||||
continue;
|
continue;
|
||||||
} else if ( ! $assoc2['isCascadeMerge']) {
|
} else if ( ! $assoc2['isCascadeMerge']) {
|
||||||
if ($this->getEntityState($other, self::STATE_DETACHED) == self::STATE_MANAGED) {
|
if ($this->getEntityState($other, self::STATE_DETACHED) !== self::STATE_MANAGED) {
|
||||||
$prop->setValue($managedCopy, $other);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
$targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
|
$targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
|
||||||
$relatedId = $targetClass->getIdentifierValues($other);
|
$relatedId = $targetClass->getIdentifierValues($other);
|
||||||
|
|
||||||
if ($targetClass->subClasses) {
|
if ($targetClass->subClasses) {
|
||||||
$entity = $this->em->find($targetClass->name, $relatedId);
|
$other = $this->em->find($targetClass->name, $relatedId);
|
||||||
} else {
|
} else {
|
||||||
$proxy = $this->em->getProxyFactory()->getProxy($assoc2['targetEntity'], $relatedId);
|
$other = $this->em->getProxyFactory()->getProxy($assoc2['targetEntity'], $relatedId);
|
||||||
$prop->setValue($managedCopy, $proxy);
|
$this->registerManaged($other, $relatedId, array());
|
||||||
$this->registerManaged($proxy, $relatedId, array());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$prop->setValue($managedCopy, $other);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$mergeCol = $prop->getValue($entity);
|
$mergeCol = $prop->getValue($entity);
|
||||||
@ -1793,6 +1790,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
public function detach($entity)
|
public function detach($entity)
|
||||||
{
|
{
|
||||||
$visited = array();
|
$visited = array();
|
||||||
|
|
||||||
$this->doDetach($entity, $visited);
|
$this->doDetach($entity, $visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1806,6 +1804,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
private function doDetach($entity, array &$visited, $noCascade = false)
|
private function doDetach($entity, array &$visited, $noCascade = false)
|
||||||
{
|
{
|
||||||
$oid = spl_object_hash($entity);
|
$oid = spl_object_hash($entity);
|
||||||
|
|
||||||
if (isset($visited[$oid])) {
|
if (isset($visited[$oid])) {
|
||||||
return; // Prevent infinite recursion
|
return; // Prevent infinite recursion
|
||||||
}
|
}
|
||||||
@ -1817,16 +1816,22 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
if ($this->isInIdentityMap($entity)) {
|
if ($this->isInIdentityMap($entity)) {
|
||||||
$this->removeFromIdentityMap($entity);
|
$this->removeFromIdentityMap($entity);
|
||||||
}
|
}
|
||||||
unset($this->entityInsertions[$oid], $this->entityUpdates[$oid],
|
|
||||||
$this->entityDeletions[$oid], $this->entityIdentifiers[$oid],
|
unset(
|
||||||
$this->entityStates[$oid], $this->originalEntityData[$oid]);
|
$this->entityInsertions[$oid],
|
||||||
|
$this->entityUpdates[$oid],
|
||||||
|
$this->entityDeletions[$oid],
|
||||||
|
$this->entityIdentifiers[$oid],
|
||||||
|
$this->entityStates[$oid],
|
||||||
|
$this->originalEntityData[$oid]
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case self::STATE_NEW:
|
case self::STATE_NEW:
|
||||||
case self::STATE_DETACHED:
|
case self::STATE_DETACHED:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$noCascade) {
|
if ( ! $noCascade) {
|
||||||
$this->cascadeDetach($entity, $visited);
|
$this->cascadeDetach($entity, $visited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1841,6 +1846,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
public function refresh($entity)
|
public function refresh($entity)
|
||||||
{
|
{
|
||||||
$visited = array();
|
$visited = array();
|
||||||
|
|
||||||
$this->doRefresh($entity, $visited);
|
$this->doRefresh($entity, $visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1854,6 +1860,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
private function doRefresh($entity, array &$visited)
|
private function doRefresh($entity, array &$visited)
|
||||||
{
|
{
|
||||||
$oid = spl_object_hash($entity);
|
$oid = spl_object_hash($entity);
|
||||||
|
|
||||||
if (isset($visited[$oid])) {
|
if (isset($visited[$oid])) {
|
||||||
return; // Prevent infinite recursion
|
return; // Prevent infinite recursion
|
||||||
}
|
}
|
||||||
@ -1861,15 +1868,16 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
$visited[$oid] = $entity; // mark visited
|
$visited[$oid] = $entity; // mark visited
|
||||||
|
|
||||||
$class = $this->em->getClassMetadata(get_class($entity));
|
$class = $this->em->getClassMetadata(get_class($entity));
|
||||||
if ($this->getEntityState($entity) == self::STATE_MANAGED) {
|
|
||||||
$this->getEntityPersister($class->name)->refresh(
|
if ($this->getEntityState($entity) !== self::STATE_MANAGED) {
|
||||||
array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
|
|
||||||
$entity
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
throw new InvalidArgumentException("Entity is not MANAGED.");
|
throw new InvalidArgumentException("Entity is not MANAGED.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->getEntityPersister($class->name)->refresh(
|
||||||
|
array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
|
||||||
|
$entity
|
||||||
|
);
|
||||||
|
|
||||||
$this->cascadeRefresh($entity, $visited);
|
$this->cascadeRefresh($entity, $visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1882,21 +1890,34 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
private function cascadeRefresh($entity, array &$visited)
|
private function cascadeRefresh($entity, array &$visited)
|
||||||
{
|
{
|
||||||
$class = $this->em->getClassMetadata(get_class($entity));
|
$class = $this->em->getClassMetadata(get_class($entity));
|
||||||
foreach ($class->associationMappings as $assoc) {
|
|
||||||
if ( ! $assoc['isCascadeRefresh']) {
|
$associationMappings = array_filter(
|
||||||
continue;
|
$class->associationMappings,
|
||||||
}
|
function ($assoc) { return $assoc['isCascadeRefresh']; }
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($associationMappings as $assoc) {
|
||||||
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
|
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
|
||||||
if ($relatedEntities instanceof Collection) {
|
|
||||||
if ($relatedEntities instanceof PersistentCollection) {
|
switch (true) {
|
||||||
|
case ($relatedEntities instanceof PersistentCollection):
|
||||||
// Unwrap so that foreach() does not initialize
|
// Unwrap so that foreach() does not initialize
|
||||||
$relatedEntities = $relatedEntities->unwrap();
|
$relatedEntities = $relatedEntities->unwrap();
|
||||||
}
|
// break; is commented intentionally!
|
||||||
foreach ($relatedEntities as $relatedEntity) {
|
|
||||||
$this->doRefresh($relatedEntity, $visited);
|
case ($relatedEntities instanceof Collection):
|
||||||
}
|
case (is_array($relatedEntities)):
|
||||||
} else if ($relatedEntities !== null) {
|
foreach ($relatedEntities as $relatedEntity) {
|
||||||
$this->doRefresh($relatedEntities, $visited);
|
$this->doRefresh($relatedEntity, $visited);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ($relatedEntities !== null):
|
||||||
|
$this->doRefresh($relatedEntities, $visited);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1910,21 +1931,34 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
private function cascadeDetach($entity, array &$visited)
|
private function cascadeDetach($entity, array &$visited)
|
||||||
{
|
{
|
||||||
$class = $this->em->getClassMetadata(get_class($entity));
|
$class = $this->em->getClassMetadata(get_class($entity));
|
||||||
foreach ($class->associationMappings as $assoc) {
|
|
||||||
if ( ! $assoc['isCascadeDetach']) {
|
$associationMappings = array_filter(
|
||||||
continue;
|
$class->associationMappings,
|
||||||
}
|
function ($assoc) { return $assoc['isCascadeDetach']; }
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($associationMappings as $assoc) {
|
||||||
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
|
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
|
||||||
if ($relatedEntities instanceof Collection) {
|
|
||||||
if ($relatedEntities instanceof PersistentCollection) {
|
switch (true) {
|
||||||
|
case ($relatedEntities instanceof PersistentCollection):
|
||||||
// Unwrap so that foreach() does not initialize
|
// Unwrap so that foreach() does not initialize
|
||||||
$relatedEntities = $relatedEntities->unwrap();
|
$relatedEntities = $relatedEntities->unwrap();
|
||||||
}
|
// break; is commented intentionally!
|
||||||
foreach ($relatedEntities as $relatedEntity) {
|
|
||||||
$this->doDetach($relatedEntity, $visited);
|
case ($relatedEntities instanceof Collection):
|
||||||
}
|
case (is_array($relatedEntities)):
|
||||||
} else if ($relatedEntities !== null) {
|
foreach ($relatedEntities as $relatedEntity) {
|
||||||
$this->doDetach($relatedEntities, $visited);
|
$this->doDetach($relatedEntity, $visited);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ($relatedEntities !== null):
|
||||||
|
$this->doDetach($relatedEntities, $visited);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1939,11 +1973,15 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
private function cascadeMerge($entity, $managedCopy, array &$visited)
|
private function cascadeMerge($entity, $managedCopy, array &$visited)
|
||||||
{
|
{
|
||||||
$class = $this->em->getClassMetadata(get_class($entity));
|
$class = $this->em->getClassMetadata(get_class($entity));
|
||||||
foreach ($class->associationMappings as $assoc) {
|
|
||||||
if ( ! $assoc['isCascadeMerge']) {
|
$associationMappings = array_filter(
|
||||||
continue;
|
$class->associationMappings,
|
||||||
}
|
function ($assoc) { return $assoc['isCascadeMerge']; }
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($associationMappings as $assoc) {
|
||||||
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
|
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
|
||||||
|
|
||||||
if ($relatedEntities instanceof Collection) {
|
if ($relatedEntities instanceof Collection) {
|
||||||
if ($relatedEntities === $class->reflFields[$assoc['fieldName']]->getValue($managedCopy)) {
|
if ($relatedEntities === $class->reflFields[$assoc['fieldName']]->getValue($managedCopy)) {
|
||||||
continue;
|
continue;
|
||||||
@ -1953,6 +1991,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
// Unwrap so that foreach() does not initialize
|
// Unwrap so that foreach() does not initialize
|
||||||
$relatedEntities = $relatedEntities->unwrap();
|
$relatedEntities = $relatedEntities->unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($relatedEntities as $relatedEntity) {
|
foreach ($relatedEntities as $relatedEntity) {
|
||||||
$this->doMerge($relatedEntity, $visited, $managedCopy, $assoc);
|
$this->doMerge($relatedEntity, $visited, $managedCopy, $assoc);
|
||||||
}
|
}
|
||||||
@ -1972,22 +2011,34 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
private function cascadePersist($entity, array &$visited)
|
private function cascadePersist($entity, array &$visited)
|
||||||
{
|
{
|
||||||
$class = $this->em->getClassMetadata(get_class($entity));
|
$class = $this->em->getClassMetadata(get_class($entity));
|
||||||
foreach ($class->associationMappings as $assoc) {
|
|
||||||
if ( ! $assoc['isCascadePersist']) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$associationMappings = array_filter(
|
||||||
|
$class->associationMappings,
|
||||||
|
function ($assoc) { return $assoc['isCascadePersist']; }
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($associationMappings as $assoc) {
|
||||||
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
|
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
|
||||||
if (($relatedEntities instanceof Collection || is_array($relatedEntities))) {
|
|
||||||
if ($relatedEntities instanceof PersistentCollection) {
|
switch (true) {
|
||||||
|
case ($relatedEntities instanceof PersistentCollection):
|
||||||
// Unwrap so that foreach() does not initialize
|
// Unwrap so that foreach() does not initialize
|
||||||
$relatedEntities = $relatedEntities->unwrap();
|
$relatedEntities = $relatedEntities->unwrap();
|
||||||
}
|
// break; is commented intentionally!
|
||||||
foreach ($relatedEntities as $relatedEntity) {
|
|
||||||
$this->doPersist($relatedEntity, $visited);
|
case ($relatedEntities instanceof Collection):
|
||||||
}
|
case (is_array($relatedEntities)):
|
||||||
} else if ($relatedEntities !== null) {
|
foreach ($relatedEntities as $relatedEntity) {
|
||||||
$this->doPersist($relatedEntities, $visited);
|
$this->doPersist($relatedEntity, $visited);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ($relatedEntities !== null):
|
||||||
|
$this->doPersist($relatedEntities, $visited);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2002,24 +2053,33 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
{
|
{
|
||||||
$class = $this->em->getClassMetadata(get_class($entity));
|
$class = $this->em->getClassMetadata(get_class($entity));
|
||||||
|
|
||||||
foreach ($class->associationMappings as $assoc) {
|
$associationMappings = array_filter(
|
||||||
if ( ! $assoc['isCascadeRemove']) {
|
$class->associationMappings,
|
||||||
continue;
|
function ($assoc) { return $assoc['isCascadeRemove']; }
|
||||||
}
|
);
|
||||||
|
|
||||||
|
foreach ($associationMappings as $assoc) {
|
||||||
if ($entity instanceof Proxy && !$entity->__isInitialized__) {
|
if ($entity instanceof Proxy && !$entity->__isInitialized__) {
|
||||||
$entity->__load();
|
$entity->__load();
|
||||||
}
|
}
|
||||||
|
|
||||||
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
|
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
|
||||||
|
|
||||||
if ($relatedEntities instanceof Collection || is_array($relatedEntities)) {
|
switch (true) {
|
||||||
// If its a PersistentCollection initialization is intended! No unwrap!
|
case ($relatedEntities instanceof Collection):
|
||||||
foreach ($relatedEntities as $relatedEntity) {
|
case (is_array($relatedEntities)):
|
||||||
$this->doRemove($relatedEntity, $visited);
|
// If its a PersistentCollection initialization is intended! No unwrap!
|
||||||
}
|
foreach ($relatedEntities as $relatedEntity) {
|
||||||
} else if ($relatedEntities !== null) {
|
$this->doRemove($relatedEntity, $visited);
|
||||||
$this->doRemove($relatedEntities, $visited);
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ($relatedEntities !== null):
|
||||||
|
$this->doRemove($relatedEntities, $visited);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2040,29 +2100,40 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
$entityName = get_class($entity);
|
$entityName = get_class($entity);
|
||||||
$class = $this->em->getClassMetadata($entityName);
|
$class = $this->em->getClassMetadata($entityName);
|
||||||
|
|
||||||
if ($lockMode == \Doctrine\DBAL\LockMode::OPTIMISTIC) {
|
switch ($lockMode) {
|
||||||
if (!$class->isVersioned) {
|
case \Doctrine\DBAL\LockMode::OPTIMISTIC;
|
||||||
throw OptimisticLockException::notVersioned($entityName);
|
if ( ! $class->isVersioned) {
|
||||||
}
|
throw OptimisticLockException::notVersioned($entityName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($lockVersion === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ($lockVersion != null) {
|
|
||||||
$entityVersion = $class->reflFields[$class->versionField]->getValue($entity);
|
$entityVersion = $class->reflFields[$class->versionField]->getValue($entity);
|
||||||
|
|
||||||
if ($entityVersion != $lockVersion) {
|
if ($entityVersion != $lockVersion) {
|
||||||
throw OptimisticLockException::lockFailedVersionMissmatch($entity, $lockVersion, $entityVersion);
|
throw OptimisticLockException::lockFailedVersionMissmatch($entity, $lockVersion, $entityVersion);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (in_array($lockMode, array(\Doctrine\DBAL\LockMode::PESSIMISTIC_READ, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE))) {
|
|
||||||
|
|
||||||
if (!$this->em->getConnection()->isTransactionActive()) {
|
break;
|
||||||
throw TransactionRequiredException::transactionRequired();
|
|
||||||
}
|
|
||||||
|
|
||||||
$oid = spl_object_hash($entity);
|
case \Doctrine\DBAL\LockMode::PESSIMISTIC_READ:
|
||||||
|
case \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE:
|
||||||
|
if (!$this->em->getConnection()->isTransactionActive()) {
|
||||||
|
throw TransactionRequiredException::transactionRequired();
|
||||||
|
}
|
||||||
|
|
||||||
$this->getEntityPersister($class->name)->lock(
|
$oid = spl_object_hash($entity);
|
||||||
array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
|
|
||||||
$lockMode
|
$this->getEntityPersister($class->name)->lock(
|
||||||
);
|
array_combine($class->getIdentifierFieldNames(), $this->entityIdentifiers[$oid]),
|
||||||
|
$lockMode
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2076,6 +2147,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
if ($this->commitOrderCalculator === null) {
|
if ($this->commitOrderCalculator === null) {
|
||||||
$this->commitOrderCalculator = new Internal\CommitOrderCalculator;
|
$this->commitOrderCalculator = new Internal\CommitOrderCalculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->commitOrderCalculator;
|
return $this->commitOrderCalculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2164,9 +2236,11 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
private function newInstance($class)
|
private function newInstance($class)
|
||||||
{
|
{
|
||||||
$entity = $class->newInstance();
|
$entity = $class->newInstance();
|
||||||
|
|
||||||
if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) {
|
if ($entity instanceof \Doctrine\Common\Persistence\ObjectManagerAware) {
|
||||||
$entity->injectObjectManager($this->em, $class);
|
$entity->injectObjectManager($this->em, $class);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2190,35 +2264,30 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
|
|
||||||
if ($class->isIdentifierComposite) {
|
if ($class->isIdentifierComposite) {
|
||||||
$id = array();
|
$id = array();
|
||||||
|
|
||||||
foreach ($class->identifier as $fieldName) {
|
foreach ($class->identifier as $fieldName) {
|
||||||
if (isset($class->associationMappings[$fieldName])) {
|
$id[$fieldName] = isset($class->associationMappings[$fieldName])
|
||||||
$id[$fieldName] = $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']];
|
? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
|
||||||
} else {
|
: $data[$fieldName];
|
||||||
$id[$fieldName] = $data[$fieldName];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$idHash = implode(' ', $id);
|
$idHash = implode(' ', $id);
|
||||||
} else {
|
} else {
|
||||||
if (isset($class->associationMappings[$class->identifier[0]])) {
|
$idHash = isset($class->associationMappings[$class->identifier[0]])
|
||||||
$idHash = $data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']];
|
? $data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']]
|
||||||
} else {
|
: $data[$class->identifier[0]];
|
||||||
/*echo $className;
|
|
||||||
\Doctrine\Common\Util\Debug::dump($data);
|
|
||||||
\Doctrine\Common\Util\Debug::dump($class->identifier);
|
|
||||||
ob_end_flush();
|
|
||||||
ob_start();*/
|
|
||||||
|
|
||||||
$idHash = $data[$class->identifier[0]];
|
|
||||||
}
|
|
||||||
$id = array($class->identifier[0] => $idHash);
|
$id = array($class->identifier[0] => $idHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($this->identityMap[$class->rootEntityName][$idHash])) {
|
if (isset($this->identityMap[$class->rootEntityName][$idHash])) {
|
||||||
$entity = $this->identityMap[$class->rootEntityName][$idHash];
|
$entity = $this->identityMap[$class->rootEntityName][$idHash];
|
||||||
$oid = spl_object_hash($entity);
|
$oid = spl_object_hash($entity);
|
||||||
|
|
||||||
if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
|
if ($entity instanceof Proxy && ! $entity->__isInitialized__) {
|
||||||
$entity->__isInitialized__ = true;
|
$entity->__isInitialized__ = true;
|
||||||
$overrideLocalValues = true;
|
$overrideLocalValues = true;
|
||||||
|
|
||||||
if ($entity instanceof NotifyPropertyChanged) {
|
if ($entity instanceof NotifyPropertyChanged) {
|
||||||
$entity->addPropertyChangedListener($this);
|
$entity->addPropertyChangedListener($this);
|
||||||
}
|
}
|
||||||
@ -2242,156 +2311,175 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
} else {
|
} else {
|
||||||
$entity = $this->newInstance($class);
|
$entity = $this->newInstance($class);
|
||||||
$oid = spl_object_hash($entity);
|
$oid = spl_object_hash($entity);
|
||||||
|
|
||||||
$this->entityIdentifiers[$oid] = $id;
|
$this->entityIdentifiers[$oid] = $id;
|
||||||
$this->entityStates[$oid] = self::STATE_MANAGED;
|
$this->entityStates[$oid] = self::STATE_MANAGED;
|
||||||
$this->originalEntityData[$oid] = $data;
|
$this->originalEntityData[$oid] = $data;
|
||||||
$this->identityMap[$class->rootEntityName][$idHash] = $entity;
|
$this->identityMap[$class->rootEntityName][$idHash] = $entity;
|
||||||
|
|
||||||
if ($entity instanceof NotifyPropertyChanged) {
|
if ($entity instanceof NotifyPropertyChanged) {
|
||||||
$entity->addPropertyChangedListener($this);
|
$entity->addPropertyChangedListener($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
$overrideLocalValues = true;
|
$overrideLocalValues = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($overrideLocalValues) {
|
if ( ! $overrideLocalValues) {
|
||||||
foreach ($data as $field => $value) {
|
return $entity;
|
||||||
if (isset($class->fieldMappings[$field])) {
|
}
|
||||||
$class->reflFields[$field]->setValue($entity, $value);
|
|
||||||
}
|
foreach ($data as $field => $value) {
|
||||||
|
if (isset($class->fieldMappings[$field])) {
|
||||||
|
$class->reflFields[$field]->setValue($entity, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading the entity right here, if its in the eager loading map get rid of it there.
|
||||||
|
unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
|
||||||
|
|
||||||
|
if (isset($this->eagerLoadingEntities[$class->rootEntityName]) && ! $this->eagerLoadingEntities[$class->rootEntityName]) {
|
||||||
|
unset($this->eagerLoadingEntities[$class->rootEntityName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properly initialize any unfetched associations, if partial objects are not allowed.
|
||||||
|
if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
|
||||||
|
return $entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($class->associationMappings as $field => $assoc) {
|
||||||
|
// Check if the association is not among the fetch-joined associations already.
|
||||||
|
if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loading the entity right here, if its in the eager loading map get rid of it there.
|
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||||
unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
|
|
||||||
|
|
||||||
if (isset($this->eagerLoadingEntities[$class->rootEntityName]) &&
|
switch (true) {
|
||||||
! $this->eagerLoadingEntities[$class->rootEntityName]) {
|
case ($assoc['type'] & ClassMetadata::TO_ONE):
|
||||||
unset($this->eagerLoadingEntities[$class->rootEntityName]);
|
if ( ! $assoc['isOwningSide']) {
|
||||||
}
|
// Inverse side of x-to-one can never be lazy
|
||||||
|
$class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity));
|
||||||
|
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$associatedId = array();
|
||||||
|
|
||||||
|
// TODO: Is this even computed right in all cases of composite keys?
|
||||||
|
foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
|
||||||
|
$joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
|
||||||
|
|
||||||
|
if ($joinColumnValue !== null) {
|
||||||
|
if ($targetClass->containsForeignIdentifier) {
|
||||||
|
$associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
|
||||||
|
} else {
|
||||||
|
$associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $associatedId) {
|
||||||
|
// Foreign key is NULL
|
||||||
|
$class->reflFields[$field]->setValue($entity, null);
|
||||||
|
$this->originalEntityData[$oid][$field] = null;
|
||||||
|
|
||||||
// Properly initialize any unfetched associations, if partial objects are not allowed.
|
|
||||||
if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
|
|
||||||
foreach ($class->associationMappings as $field => $assoc) {
|
|
||||||
// Check if the association is not among the fetch-joined associations already.
|
|
||||||
if (isset($hints['fetchAlias']) && isset($hints['fetched'][$hints['fetchAlias']][$field])) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
|
if ( ! isset($hints['fetchMode'][$class->name][$field])) {
|
||||||
|
$hints['fetchMode'][$class->name][$field] = $assoc['fetch'];
|
||||||
if ($assoc['type'] & ClassMetadata::TO_ONE) {
|
|
||||||
if ($assoc['isOwningSide']) {
|
|
||||||
$associatedId = array();
|
|
||||||
// TODO: Is this even computed right in all cases of composite keys?
|
|
||||||
foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
|
|
||||||
$joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
|
|
||||||
if ($joinColumnValue !== null) {
|
|
||||||
if ($targetClass->containsForeignIdentifier) {
|
|
||||||
$associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
|
|
||||||
} else {
|
|
||||||
$associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( ! $associatedId) {
|
|
||||||
// Foreign key is NULL
|
|
||||||
$class->reflFields[$field]->setValue($entity, null);
|
|
||||||
$this->originalEntityData[$oid][$field] = null;
|
|
||||||
} else {
|
|
||||||
if (!isset($hints['fetchMode'][$class->name][$field])) {
|
|
||||||
$hints['fetchMode'][$class->name][$field] = $assoc['fetch'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Foreign key is set
|
|
||||||
// Check identity map first
|
|
||||||
// FIXME: Can break easily with composite keys if join column values are in
|
|
||||||
// wrong order. The correct order is the one in ClassMetadata#identifier.
|
|
||||||
$relatedIdHash = implode(' ', $associatedId);
|
|
||||||
if (isset($this->identityMap[$targetClass->rootEntityName][$relatedIdHash])) {
|
|
||||||
$newValue = $this->identityMap[$targetClass->rootEntityName][$relatedIdHash];
|
|
||||||
|
|
||||||
// if this is an uninitialized proxy, we are deferring eager loads,
|
|
||||||
// this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
|
|
||||||
// then we cann append this entity for eager loading!
|
|
||||||
if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER &&
|
|
||||||
isset($hints['deferEagerLoad']) &&
|
|
||||||
!$targetClass->isIdentifierComposite &&
|
|
||||||
$newValue instanceof Proxy &&
|
|
||||||
$newValue->__isInitialized__ === false) {
|
|
||||||
|
|
||||||
$this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($targetClass->subClasses) {
|
|
||||||
// If it might be a subtype, it can not be lazy. There isn't even
|
|
||||||
// a way to solve this with deferred eager loading, which means putting
|
|
||||||
// an entity with subclasses at a *-to-one location is really bad! (performance-wise)
|
|
||||||
$newValue = $this->getEntityPersister($assoc['targetEntity'])
|
|
||||||
->loadOneToOneEntity($assoc, $entity, $associatedId);
|
|
||||||
} else {
|
|
||||||
// Deferred eager load only works for single identifier classes
|
|
||||||
|
|
||||||
if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER) {
|
|
||||||
if (isset($hints['deferEagerLoad']) && !$targetClass->isIdentifierComposite) {
|
|
||||||
// TODO: Is there a faster approach?
|
|
||||||
$this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
|
|
||||||
|
|
||||||
$newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
|
|
||||||
} else {
|
|
||||||
// TODO: This is very imperformant, ignore it?
|
|
||||||
$newValue = $this->em->find($assoc['targetEntity'], $associatedId);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
|
|
||||||
}
|
|
||||||
// PERF: Inlined & optimized code from UnitOfWork#registerManaged()
|
|
||||||
$newValueOid = spl_object_hash($newValue);
|
|
||||||
$this->entityIdentifiers[$newValueOid] = $associatedId;
|
|
||||||
$this->identityMap[$targetClass->rootEntityName][$relatedIdHash] = $newValue;
|
|
||||||
$this->entityStates[$newValueOid] = self::STATE_MANAGED;
|
|
||||||
// make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->originalEntityData[$oid][$field] = $newValue;
|
|
||||||
$class->reflFields[$field]->setValue($entity, $newValue);
|
|
||||||
|
|
||||||
if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
|
|
||||||
$inverseAssoc = $targetClass->associationMappings[$assoc['inversedBy']];
|
|
||||||
$targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($newValue, $entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Inverse side of x-to-one can never be lazy
|
|
||||||
$class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc['targetEntity'])
|
|
||||||
->loadOneToOneEntity($assoc, $entity));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Inject collection
|
|
||||||
$pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection);
|
|
||||||
$pColl->setOwner($entity, $assoc);
|
|
||||||
|
|
||||||
$reflField = $class->reflFields[$field];
|
|
||||||
$reflField->setValue($entity, $pColl);
|
|
||||||
|
|
||||||
if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
|
|
||||||
$this->loadCollection($pColl);
|
|
||||||
$pColl->takeSnapshot();
|
|
||||||
} else {
|
|
||||||
$pColl->setInitialized(false);
|
|
||||||
}
|
|
||||||
$this->originalEntityData[$oid][$field] = $pColl;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Foreign key is set
|
||||||
|
// Check identity map first
|
||||||
|
// FIXME: Can break easily with composite keys if join column values are in
|
||||||
|
// wrong order. The correct order is the one in ClassMetadata#identifier.
|
||||||
|
$relatedIdHash = implode(' ', $associatedId);
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case (isset($this->identityMap[$targetClass->rootEntityName][$relatedIdHash])):
|
||||||
|
$newValue = $this->identityMap[$targetClass->rootEntityName][$relatedIdHash];
|
||||||
|
|
||||||
|
// if this is an uninitialized proxy, we are deferring eager loads,
|
||||||
|
// this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
|
||||||
|
// then we cann append this entity for eager loading!
|
||||||
|
if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER &&
|
||||||
|
isset($hints['deferEagerLoad']) &&
|
||||||
|
!$targetClass->isIdentifierComposite &&
|
||||||
|
$newValue instanceof Proxy &&
|
||||||
|
$newValue->__isInitialized__ === false) {
|
||||||
|
|
||||||
|
$this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ($targetClass->subClasses):
|
||||||
|
// If it might be a subtype, it can not be lazy. There isn't even
|
||||||
|
// a way to solve this with deferred eager loading, which means putting
|
||||||
|
// an entity with subclasses at a *-to-one location is really bad! (performance-wise)
|
||||||
|
$newValue = $this->getEntityPersister($assoc['targetEntity'])->loadOneToOneEntity($assoc, $entity, $associatedId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
switch (true) {
|
||||||
|
// We are negating the condition here. Other cases will assume it is valid!
|
||||||
|
case ($hints['fetchMode'][$class->name][$field] !== ClassMetadata::FETCH_EAGER):
|
||||||
|
$newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Deferred eager load only works for single identifier classes
|
||||||
|
case (isset($hints['deferEagerLoad']) && ! $targetClass->isIdentifierComposite):
|
||||||
|
// TODO: Is there a faster approach?
|
||||||
|
$this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
|
||||||
|
|
||||||
|
$newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// TODO: This is very imperformant, ignore it?
|
||||||
|
$newValue = $this->em->find($assoc['targetEntity'], $associatedId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PERF: Inlined & optimized code from UnitOfWork#registerManaged()
|
||||||
|
$newValueOid = spl_object_hash($newValue);
|
||||||
|
$this->entityIdentifiers[$newValueOid] = $associatedId;
|
||||||
|
$this->identityMap[$targetClass->rootEntityName][$relatedIdHash] = $newValue;
|
||||||
|
$this->entityStates[$newValueOid] = self::STATE_MANAGED;
|
||||||
|
// make sure that when an proxy is then finally loaded, $this->originalEntityData is set also!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->originalEntityData[$oid][$field] = $newValue;
|
||||||
|
$class->reflFields[$field]->setValue($entity, $newValue);
|
||||||
|
|
||||||
|
if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
|
||||||
|
$inverseAssoc = $targetClass->associationMappings[$assoc['inversedBy']];
|
||||||
|
$targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($newValue, $entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Inject collection
|
||||||
|
$pColl = new PersistentCollection($this->em, $targetClass, new ArrayCollection);
|
||||||
|
$pColl->setOwner($entity, $assoc);
|
||||||
|
$pColl->setInitialized(false);
|
||||||
|
|
||||||
|
$reflField = $class->reflFields[$field];
|
||||||
|
$reflField->setValue($entity, $pColl);
|
||||||
|
|
||||||
|
if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
|
||||||
|
$this->loadCollection($pColl);
|
||||||
|
$pColl->takeSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->originalEntityData[$oid][$field] = $pColl;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
|
|
||||||
if (isset($class->lifecycleCallbacks[Events::postLoad])) {
|
|
||||||
$class->invokeLifecycleCallbacks(Events::postLoad, $entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->evm->hasListeners(Events::postLoad)) {
|
|
||||||
$this->evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->em));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2564,7 +2652,7 @@ class UnitOfWork implements PropertyChangedListener
|
|||||||
*
|
*
|
||||||
* @param string $entityName The name of the Entity.
|
* @param string $entityName The name of the Entity.
|
||||||
*
|
*
|
||||||
* @return Doctrine\ORM\Persisters\AbstractEntityPersister
|
* @return Doctrine\ORM\Persisters\BasicEntityPersister
|
||||||
*/
|
*/
|
||||||
public function getEntityPersister($entityName)
|
public function getEntityPersister($entityName)
|
||||||
{
|
{
|
||||||
|
@ -92,4 +92,10 @@ class CompositePrimaryKeyTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
|
|
||||||
$this->assertEquals(1, count($tours));
|
$this->assertEquals(1, count($tours));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSpecifiyUnknownIdentifierPrimaryKeyFails()
|
||||||
|
{
|
||||||
|
$this->setExpectedException('Doctrine\ORM\ORMException', 'The identifier long is missing for a query of Doctrine\Tests\Models\Navigation\NavPointOfInterest');
|
||||||
|
$poi = $this->_em->find('Doctrine\Tests\Models\Navigation\NavPointOfInterest', array('key1' => 100));
|
||||||
|
}
|
||||||
}
|
}
|
@ -29,7 +29,6 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
|
$class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup');
|
||||||
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
|
$class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY;
|
||||||
|
|
||||||
|
|
||||||
$this->loadFixture();
|
$this->loadFixture();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,17 +255,18 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||||
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
||||||
|
|
||||||
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
|
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
|
||||||
|
|
||||||
$queryCount = $this->getCurrentQueryCount();
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
$this->assertTrue($user->groups->contains($group));
|
$this->assertTrue($user->groups->contains($group));
|
||||||
$this->assertEquals($queryCount+1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
|
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
|
||||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||||
|
|
||||||
$group = new \Doctrine\Tests\Models\CMS\CmsGroup();
|
$group = new \Doctrine\Tests\Models\CMS\CmsGroup();
|
||||||
$group->name = "A New group!";
|
$group->name = "A New group!";
|
||||||
|
|
||||||
$queryCount = $this->getCurrentQueryCount();
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
$this->assertFalse($user->groups->contains($group));
|
$this->assertFalse($user->groups->contains($group));
|
||||||
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of new entity should cause no query to be executed.");
|
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Checking for contains of new entity should cause no query to be executed.");
|
||||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||||
@ -275,8 +275,9 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$this->_em->flush();
|
$this->_em->flush();
|
||||||
|
|
||||||
$queryCount = $this->getCurrentQueryCount();
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
$this->assertFalse($user->groups->contains($group));
|
$this->assertFalse($user->groups->contains($group));
|
||||||
$this->assertEquals($queryCount+1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
|
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Checking for contains of managed entity should cause one query to be executed.");
|
||||||
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,6 +305,107 @@ 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.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function testRemoveElementOneToMany()
|
||||||
|
{
|
||||||
|
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||||
|
$this->assertFalse($user->articles->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
||||||
|
|
||||||
|
$article = $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId);
|
||||||
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
|
$user->articles->removeElement($article);
|
||||||
|
|
||||||
|
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||||
|
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount());
|
||||||
|
|
||||||
|
$article = new \Doctrine\Tests\Models\CMS\CmsArticle();
|
||||||
|
$article->topic = "Testnew";
|
||||||
|
$article->text = "blub";
|
||||||
|
|
||||||
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
|
$user->articles->removeElement($article);
|
||||||
|
|
||||||
|
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing a new entity should cause no query to be executed.");
|
||||||
|
|
||||||
|
$this->_em->persist($article);
|
||||||
|
$this->_em->flush();
|
||||||
|
|
||||||
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
|
$user->articles->removeElement($article);
|
||||||
|
|
||||||
|
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a managed entity should cause one query to be executed.");
|
||||||
|
$this->assertFalse($user->articles->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function testRemoveElementManyToMany()
|
||||||
|
{
|
||||||
|
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||||
|
$this->assertFalse($user->groups->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
||||||
|
|
||||||
|
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
|
||||||
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
|
$user->groups->removeElement($group);
|
||||||
|
|
||||||
|
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a managed entity should cause one query to be executed.");
|
||||||
|
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||||
|
|
||||||
|
$group = new \Doctrine\Tests\Models\CMS\CmsGroup();
|
||||||
|
$group->name = "A New group!";
|
||||||
|
|
||||||
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
|
$user->groups->removeElement($group);
|
||||||
|
|
||||||
|
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing new entity should cause no query to be executed.");
|
||||||
|
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||||
|
|
||||||
|
$this->_em->persist($group);
|
||||||
|
$this->_em->flush();
|
||||||
|
|
||||||
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
|
$user->groups->removeElement($group);
|
||||||
|
|
||||||
|
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a managed entity should cause one query to be executed.");
|
||||||
|
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function testRemoveElementManyToManyInverse()
|
||||||
|
{
|
||||||
|
$group = $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId);
|
||||||
|
$this->assertFalse($group->users->isInitialized(), "Pre-Condition: Collection is not initialized.");
|
||||||
|
|
||||||
|
$user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId);
|
||||||
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
|
$group->users->removeElement($user);
|
||||||
|
|
||||||
|
$this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Removing a managed entity should cause one query to be executed.");
|
||||||
|
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||||
|
|
||||||
|
$newUser = new \Doctrine\Tests\Models\CMS\CmsUser();
|
||||||
|
$newUser->name = "A New group!";
|
||||||
|
|
||||||
|
$queryCount = $this->getCurrentQueryCount();
|
||||||
|
|
||||||
|
$group->users->removeElement($newUser);
|
||||||
|
|
||||||
|
$this->assertEquals($queryCount, $this->getCurrentQueryCount(), "Removing a new entity should cause no query to be executed.");
|
||||||
|
$this->assertFalse($user->groups->isInitialized(), "Post-Condition: Collection is not initialized.");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group DDC-1399
|
* @group DDC-1399
|
||||||
*/
|
*/
|
||||||
|
146
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1509Test.php
Normal file
146
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1509Test.php
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||||
|
|
||||||
|
use Doctrine\ORM\UnitOfWork;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-1509
|
||||||
|
*/
|
||||||
|
class DDC1509Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->_schemaTool->createSchema(array(
|
||||||
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1509AbstractFile'),
|
||||||
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1509File'),
|
||||||
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC1509Picture'),
|
||||||
|
));
|
||||||
|
} catch (\Exception $ignored) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFailingCase()
|
||||||
|
{
|
||||||
|
$file = new DDC1509File;
|
||||||
|
$thumbnail = new DDC1509File;
|
||||||
|
|
||||||
|
$picture = new DDC1509Picture;
|
||||||
|
$picture->setFile($file);
|
||||||
|
$picture->setThumbnail($thumbnail);
|
||||||
|
|
||||||
|
|
||||||
|
/* @var $em \Doctrine\ORM\EntityManager */
|
||||||
|
$em = $this->_em;
|
||||||
|
$em->persist($picture);
|
||||||
|
$em->flush();
|
||||||
|
$em->clear();
|
||||||
|
|
||||||
|
$id = $picture->getPictureId();
|
||||||
|
|
||||||
|
$pic = $em->merge($picture);
|
||||||
|
/* @var $pic DDC1509Picture */
|
||||||
|
|
||||||
|
$this->assertNotNull($pic->getThumbnail());
|
||||||
|
$this->assertNotNull($pic->getFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
*/
|
||||||
|
class DDC1509Picture
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column(type="integer")
|
||||||
|
* @Id
|
||||||
|
* @GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ManyToOne(targetEntity="DDC1509AbstractFile", cascade={"persist", "remove"})
|
||||||
|
*/
|
||||||
|
private $thumbnail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ManyToOne(targetEntity="DDC1509AbstractFile", cascade={"persist", "remove"})
|
||||||
|
*/
|
||||||
|
private $file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get pictureId
|
||||||
|
*/
|
||||||
|
public function getPictureId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set file
|
||||||
|
*/
|
||||||
|
public function setFile($value = null)
|
||||||
|
{
|
||||||
|
$this->file = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get file
|
||||||
|
*/
|
||||||
|
public function getFile()
|
||||||
|
{
|
||||||
|
return $this->file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getThumbnail()
|
||||||
|
{
|
||||||
|
return $this->thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setThumbnail($thumbnail)
|
||||||
|
{
|
||||||
|
$this->thumbnail = $thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
* @InheritanceType("SINGLE_TABLE")
|
||||||
|
* @DiscriminatorColumn(name="discr", type="string")
|
||||||
|
* @DiscriminatorMap({"file" = "DDC1509File"})
|
||||||
|
*/
|
||||||
|
class DDC1509AbstractFile
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column(type="integer")
|
||||||
|
* @Id
|
||||||
|
* @GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get fileId
|
||||||
|
*/
|
||||||
|
public function getFileId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
*/
|
||||||
|
class DDC1509File extends DDC1509AbstractFile
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -373,6 +373,25 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
|
|
||||||
$this->assertEquals(ClassMetadataInfo::GENERATOR_TYPE_NONE, $class->generatorType);
|
$this->assertEquals(ClassMetadataInfo::GENERATOR_TYPE_NONE, $class->generatorType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-1170
|
||||||
|
*/
|
||||||
|
public function testIdentifierColumnDefinition()
|
||||||
|
{
|
||||||
|
|
||||||
|
$class = $this->createClassMetadata(__NAMESPACE__ . '\DDC1170Entity');
|
||||||
|
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('id', $class->fieldMappings);
|
||||||
|
$this->assertArrayHasKey('value', $class->fieldMappings);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('columnDefinition', $class->fieldMappings['id']);
|
||||||
|
$this->assertArrayHasKey('columnDefinition', $class->fieldMappings['value']);
|
||||||
|
|
||||||
|
$this->assertEquals("INT unsigned NOT NULL", $class->fieldMappings['id']['columnDefinition']);
|
||||||
|
$this->assertEquals("VARCHAR(255) NOT NULL", $class->fieldMappings['value']['columnDefinition']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -598,3 +617,64 @@ class Dog extends Animal
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
*/
|
||||||
|
class DDC1170Entity
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $value
|
||||||
|
*/
|
||||||
|
function __construct($value = null)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Id
|
||||||
|
* @GeneratedValue(strategy="NONE")
|
||||||
|
* @Column(type="integer", columnDefinition = "INT unsigned NOT NULL")
|
||||||
|
**/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column(columnDefinition = "VARCHAR(255) NOT NULL")
|
||||||
|
*/
|
||||||
|
private $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValue()
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function loadMetadata(ClassMetadataInfo $metadata)
|
||||||
|
{
|
||||||
|
$metadata->mapField(array(
|
||||||
|
'id' => true,
|
||||||
|
'fieldName' => 'id',
|
||||||
|
'columnDefinition' => 'INT unsigned NOT NULL',
|
||||||
|
));
|
||||||
|
|
||||||
|
$metadata->mapField(array(
|
||||||
|
'fieldName' => 'value',
|
||||||
|
'columnDefinition' => 'VARCHAR(255) NOT NULL'
|
||||||
|
));
|
||||||
|
|
||||||
|
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,6 +9,7 @@ use Doctrine\Tests\Mocks\ConnectionMock;
|
|||||||
use Doctrine\Tests\Mocks\DriverMock;
|
use Doctrine\Tests\Mocks\DriverMock;
|
||||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||||
use Doctrine\Common\EventManager;
|
use Doctrine\Common\EventManager;
|
||||||
|
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||||
|
|
||||||
require_once __DIR__ . '/../../TestInit.php';
|
require_once __DIR__ . '/../../TestInit.php';
|
||||||
|
|
||||||
@ -82,6 +83,51 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
$this->assertTrue($h1);
|
$this->assertTrue($h1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-1512
|
||||||
|
*/
|
||||||
|
public function testIsTransient()
|
||||||
|
{
|
||||||
|
$cmf = new ClassMetadataFactory();
|
||||||
|
$driver = $this->getMock('Doctrine\ORM\Mapping\Driver\Driver');
|
||||||
|
$driver->expects($this->at(0))
|
||||||
|
->method('isTransient')
|
||||||
|
->with($this->equalTo('Doctrine\Tests\Models\CMS\CmsUser'))
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
$driver->expects($this->at(1))
|
||||||
|
->method('isTransient')
|
||||||
|
->with($this->equalTo('Doctrine\Tests\Models\CMS\CmsArticle'))
|
||||||
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
|
$em = $this->_createEntityManager($driver);
|
||||||
|
|
||||||
|
$this->assertTrue($em->getMetadataFactory()->isTransient('Doctrine\Tests\Models\CMS\CmsUser'));
|
||||||
|
$this->assertFalse($em->getMetadataFactory()->isTransient('Doctrine\Tests\Models\CMS\CmsArticle'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-1512
|
||||||
|
*/
|
||||||
|
public function testIsTransientEntityNamespace()
|
||||||
|
{
|
||||||
|
$cmf = new ClassMetadataFactory();
|
||||||
|
$driver = $this->getMock('Doctrine\ORM\Mapping\Driver\Driver');
|
||||||
|
$driver->expects($this->at(0))
|
||||||
|
->method('isTransient')
|
||||||
|
->with($this->equalTo('Doctrine\Tests\Models\CMS\CmsUser'))
|
||||||
|
->will($this->returnValue(true));
|
||||||
|
$driver->expects($this->at(1))
|
||||||
|
->method('isTransient')
|
||||||
|
->with($this->equalTo('Doctrine\Tests\Models\CMS\CmsArticle'))
|
||||||
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
|
$em = $this->_createEntityManager($driver);
|
||||||
|
$em->getConfiguration()->addEntityNamespace('CMS', 'Doctrine\Tests\Models\CMS');
|
||||||
|
|
||||||
|
$this->assertTrue($em->getMetadataFactory()->isTransient('CMS:CmsUser'));
|
||||||
|
$this->assertFalse($em->getMetadataFactory()->isTransient('CMS:CmsArticle'));
|
||||||
|
}
|
||||||
|
|
||||||
protected function _createEntityManager($metadataDriver)
|
protected function _createEntityManager($metadataDriver)
|
||||||
{
|
{
|
||||||
$driverMock = new DriverMock();
|
$driverMock = new DriverMock();
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||||
|
|
||||||
|
$metadata->mapField(array(
|
||||||
|
'id' => true,
|
||||||
|
'fieldName' => 'id',
|
||||||
|
'columnDefinition' => 'INT unsigned NOT NULL',
|
||||||
|
));
|
||||||
|
|
||||||
|
$metadata->mapField(array(
|
||||||
|
'fieldName' => 'value',
|
||||||
|
'columnDefinition' => 'VARCHAR(255) NOT NULL'
|
||||||
|
));
|
||||||
|
|
||||||
|
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE);
|
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||||
|
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||||
|
|
||||||
|
<entity name="Doctrine\Tests\ORM\Mapping\DDC1170Entity">
|
||||||
|
<id name="id" column-definition="INT unsigned NOT NULL">
|
||||||
|
<generator strategy="NONE"/>
|
||||||
|
</id>
|
||||||
|
|
||||||
|
<field name="value" column-definition="VARCHAR(255) NOT NULL"/>
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
</doctrine-mapping>
|
@ -0,0 +1,10 @@
|
|||||||
|
Doctrine\Tests\ORM\Mapping\DDC1170Entity:
|
||||||
|
type: entity
|
||||||
|
id:
|
||||||
|
id:
|
||||||
|
columnDefinition: INT unsigned NOT NULL
|
||||||
|
generator:
|
||||||
|
strategy: NONE
|
||||||
|
fields:
|
||||||
|
value:
|
||||||
|
columnDefinition: VARCHAR(255) NOT NULL
|
@ -40,7 +40,14 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
$query->setHint($name, $value);
|
$query->setHint($name, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::assertEquals($sqlToBeConfirmed, $query->getSQL());
|
$sqlGenerated = $query->getSQL();
|
||||||
|
|
||||||
|
parent::assertEquals(
|
||||||
|
$sqlToBeConfirmed,
|
||||||
|
$sqlGenerated,
|
||||||
|
sprintf('"%s" is not equal of "%s"', $sqlGenerated, $sqlToBeConfirmed)
|
||||||
|
);
|
||||||
|
|
||||||
$query->free();
|
$query->free();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->fail($e->getMessage() ."\n".$e->getTraceAsString());
|
$this->fail($e->getMessage() ."\n".$e->getTraceAsString());
|
||||||
@ -444,8 +451,8 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
public function testSupportsSingleValuedInExpressionWithoutSpacesInWherePart()
|
public function testSupportsSingleValuedInExpressionWithoutSpacesInWherePart()
|
||||||
{
|
{
|
||||||
$this->assertSqlGeneration(
|
$this->assertSqlGeneration(
|
||||||
"SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN(46)",
|
"SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE IDENTITY(u.email) IN(46)",
|
||||||
"SELECT c0_.name AS name0 FROM cms_users c0_ WHERE c0_.id IN (46)"
|
"SELECT c0_.name AS name0 FROM cms_users c0_ WHERE c0_.email_id IN (46)"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,8 +467,8 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
public function testSupportsNotInExpressionInWherePart()
|
public function testSupportsNotInExpressionInWherePart()
|
||||||
{
|
{
|
||||||
$this->assertSqlGeneration(
|
$this->assertSqlGeneration(
|
||||||
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN (1)',
|
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :id NOT IN (1)',
|
||||||
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.id NOT IN (1)'
|
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE ? NOT IN (1)'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,43 +536,71 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSupportsMemberOfExpression()
|
public function testSupportsMemberOfExpressionOneToMany()
|
||||||
{
|
{
|
||||||
// "Get all users who have $phone as a phonenumber." (*cough* doesnt really make sense...)
|
// "Get all users who have $phone as a phonenumber." (*cough* doesnt really make sense...)
|
||||||
$q1 = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers');
|
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers');
|
||||||
$q1->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
|
$q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
|
||||||
|
|
||||||
$phone = new \Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
$phone = new \Doctrine\Tests\Models\CMS\CmsPhonenumber;
|
||||||
$phone->phonenumber = 101;
|
$phone->phonenumber = 101;
|
||||||
$q1->setParameter('param', $phone);
|
$q->setParameter('param', $phone);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_phonenumbers c1_ WHERE c0_.id = c1_.user_id AND c1_.phonenumber = ?)',
|
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_phonenumbers c1_ WHERE c0_.id = c1_.user_id AND c1_.phonenumber = ?)',
|
||||||
$q1->getSql()
|
$q->getSql()
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSupportsMemberOfExpressionManyToMany()
|
||||||
|
{
|
||||||
// "Get all users who are members of $group."
|
// "Get all users who are members of $group."
|
||||||
$q2 = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.groups');
|
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.groups');
|
||||||
$q2->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
|
$q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
|
||||||
|
|
||||||
$group = new \Doctrine\Tests\Models\CMS\CmsGroup;
|
$group = new \Doctrine\Tests\Models\CMS\CmsGroup;
|
||||||
$group->id = 101;
|
$group->id = 101;
|
||||||
$q2->setParameter('param', $group);
|
$q->setParameter('param', $group);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = ?)',
|
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = ?)',
|
||||||
$q2->getSql()
|
$q->getSql()
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSupportsMemberOfExpressionSelfReferencing()
|
||||||
|
{
|
||||||
// "Get all persons who have $person as a friend."
|
// "Get all persons who have $person as a friend."
|
||||||
// Tough one: Many-many self-referencing ("friends") with class table inheritance
|
// Tough one: Many-many self-referencing ("friends") with class table inheritance
|
||||||
$q3 = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p WHERE :param MEMBER OF p.friends');
|
$q = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p WHERE :param MEMBER OF p.friends');
|
||||||
$person = new \Doctrine\Tests\Models\Company\CompanyPerson;
|
$person = new \Doctrine\Tests\Models\Company\CompanyPerson;
|
||||||
$this->_em->getClassMetadata(get_class($person))->setIdentifierValues($person, array('id' => 101));
|
$this->_em->getClassMetadata(get_class($person))->setIdentifierValues($person, array('id' => 101));
|
||||||
$q3->setParameter('param', $person);
|
$q->setParameter('param', $person);
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c1_.car_id AS car_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.friend_id = c4_.id WHERE c3_.person_id = c0_.id AND c4_.id = ?)',
|
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c1_.car_id AS car_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.friend_id = c4_.id WHERE c3_.person_id = c0_.id AND c4_.id = ?)',
|
||||||
$q3->getSql()
|
$q->getSql()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSupportsMemberOfWithSingleValuedAssociation()
|
||||||
|
{
|
||||||
|
// Impossible example, but it illustrates the purpose
|
||||||
|
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.email MEMBER OF u.groups');
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = c0_.email_id)',
|
||||||
|
$q->getSql()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSupportsMemberOfWithIdentificationVariable()
|
||||||
|
{
|
||||||
|
// Impossible example, but it illustrates the purpose
|
||||||
|
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u MEMBER OF u.groups');
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = c0_.id)',
|
||||||
|
$q->getSql()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1335,6 +1370,28 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-1236
|
||||||
|
*/
|
||||||
|
public function testGroupBySupportsResultVariable()
|
||||||
|
{
|
||||||
|
$this->assertSqlGeneration(
|
||||||
|
'SELECT u, u.status AS st FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY st',
|
||||||
|
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3, c0_.status AS status4 FROM cms_users c0_ GROUP BY status4'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-1236
|
||||||
|
*/
|
||||||
|
public function testGroupBySupportsIdentificationVariable()
|
||||||
|
{
|
||||||
|
$this->assertSqlGeneration(
|
||||||
|
'SELECT u AS user FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY user',
|
||||||
|
'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ GROUP BY id0, status1, username2, name3'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testCustomTypeValueSql()
|
public function testCustomTypeValueSql()
|
||||||
{
|
{
|
||||||
if (DBALType::hasType('negative_to_positive')) {
|
if (DBALType::hasType('negative_to_positive')) {
|
||||||
|
@ -52,6 +52,8 @@ abstract class OrmTestCase extends DoctrineTestCase
|
|||||||
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
|
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
\Doctrine\Common\Annotations\AnnotationRegistry::registerFile(
|
||||||
|
__DIR__ . "/../../../lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php");
|
||||||
return new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, (array)$paths);
|
return new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($reader, (array)$paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user