mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
56 Commits
old-protot
...
v2.6.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2b4dd71d2 | ||
|
|
36e6a73d5b | ||
|
|
e26158a45e | ||
|
|
3cfcd6a856 | ||
|
|
ff68806bfa | ||
|
|
4192c3abf4 | ||
|
|
ac1e1c7d23 | ||
|
|
9ab999618c | ||
|
|
f2666a472f | ||
|
|
ceda5d3bc7 | ||
|
|
6d81d519b6 | ||
|
|
88d1d79516 | ||
|
|
cfc6cfd1a3 | ||
|
|
6b7d67b427 | ||
|
|
b6d08b15c0 | ||
|
|
01f89a8cdc | ||
|
|
efd7a5dca6 | ||
|
|
7ba0290643 | ||
|
|
8ceb47178b | ||
|
|
2560d4f419 | ||
|
|
87ee409783 | ||
|
|
d47c1f3e9b | ||
|
|
b952dac339 | ||
|
|
ffb7d4c79c | ||
|
|
e68717b725 | ||
|
|
30a063ef9d | ||
|
|
35c3669ebc | ||
|
|
23f4f03575 | ||
|
|
a912fc09be | ||
|
|
a736a3713b | ||
|
|
f2da5bc93e | ||
|
|
2905b435db | ||
|
|
48ca6dbcec | ||
|
|
15a4302902 | ||
|
|
1f82a20312 | ||
|
|
fc943b70f6 | ||
|
|
f36470941c | ||
|
|
ae6d80daab | ||
|
|
44e82e2720 | ||
|
|
e94467d6da | ||
|
|
794c7708e8 | ||
|
|
8e73926359 | ||
|
|
8fc1d74820 | ||
|
|
496c6a9f03 | ||
|
|
7873f700b0 | ||
|
|
46c0861f45 | ||
|
|
5149c0ff25 | ||
|
|
cf99d62472 | ||
|
|
5878797eae | ||
|
|
8c2d090dc8 | ||
|
|
3f772eac32 | ||
|
|
62c952d258 | ||
|
|
c2f698e56e | ||
|
|
40f2a3efba | ||
|
|
333b9c0b99 | ||
|
|
90d19b4131 |
@@ -1,5 +1,12 @@
|
||||
# Upgrade to 2.6
|
||||
|
||||
## Added `Doctrine\ORM\EntityRepository::count()` method
|
||||
|
||||
`Doctrine\ORM\EntityRepository::count()` has been added. This new method has different
|
||||
signature than `Countable::count()` (required parameter) and therefore are not compatible.
|
||||
If your repository implemented the `Countable` interface, you will have to use
|
||||
`$repository->count([])` instead and not implement `Countable` interface anymore.
|
||||
|
||||
## Minor BC BREAK: `Doctrine\ORM\Tools\Console\ConsoleRunner` is now final
|
||||
|
||||
Since it's just an utilitarian class and should not be inherited.
|
||||
|
||||
@@ -25,6 +25,13 @@ Work that have not yet been persisted are lost.
|
||||
Not calling ``EntityManager#flush()`` will lead to all changes
|
||||
during that request being lost.
|
||||
|
||||
.. note::
|
||||
|
||||
Doctrine does NEVER touch the public API of methods in your entity
|
||||
classes (like getters and setters) nor the constructor method.
|
||||
Instead, it uses reflection to get/set data from/to your entity objects.
|
||||
When Doctrine fetches data from DB and saves it back,
|
||||
any code put in your get/set methods won't be implicitly taken into account.
|
||||
|
||||
Entities and the Identity Map
|
||||
-----------------------------
|
||||
|
||||
@@ -75,6 +75,10 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
$data = $this->uow->getOriginalEntityData($entity);
|
||||
$data = array_merge($data, $metadata->getIdentifierValues($entity)); // why update has no identifier values ?
|
||||
|
||||
if ($metadata->isVersioned) {
|
||||
$data[$metadata->versionField] = $metadata->getFieldValue($entity, $metadata->versionField);
|
||||
}
|
||||
|
||||
foreach ($metadata->associationMappings as $name => $assoc) {
|
||||
if ( ! isset($data[$name])) {
|
||||
continue;
|
||||
|
||||
@@ -23,6 +23,7 @@ use Doctrine\Common\EventManager;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Proxy\ProxyFactory;
|
||||
use Doctrine\ORM\Query\FilterCollection;
|
||||
@@ -380,6 +381,10 @@ use Throwable;
|
||||
{
|
||||
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
|
||||
|
||||
if ($lockMode !== null) {
|
||||
$this->checkLockRequirements($lockMode, $class);
|
||||
}
|
||||
|
||||
if ( ! is_array($id)) {
|
||||
if ($class->isIdentifierComposite) {
|
||||
throw ORMInvalidArgumentException::invalidCompositeIdentifier();
|
||||
@@ -441,10 +446,6 @@ use Throwable;
|
||||
|
||||
switch (true) {
|
||||
case LockMode::OPTIMISTIC === $lockMode:
|
||||
if ( ! $class->isVersioned) {
|
||||
throw OptimisticLockException::notVersioned($class->name);
|
||||
}
|
||||
|
||||
$entity = $persister->load($sortedId);
|
||||
|
||||
$unitOfWork->lock($entity, $lockMode, $lockVersion);
|
||||
@@ -453,10 +454,6 @@ use Throwable;
|
||||
|
||||
case LockMode::PESSIMISTIC_READ === $lockMode:
|
||||
case LockMode::PESSIMISTIC_WRITE === $lockMode:
|
||||
if ( ! $this->getConnection()->isTransactionActive()) {
|
||||
throw TransactionRequiredException::transactionRequired();
|
||||
}
|
||||
|
||||
return $persister->load($sortedId, null, null, [], $lockMode);
|
||||
|
||||
default:
|
||||
@@ -915,4 +912,26 @@ use Throwable;
|
||||
{
|
||||
return null !== $this->filterCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $lockMode
|
||||
* @param ClassMetadata $class
|
||||
* @throws OptimisticLockException
|
||||
* @throws TransactionRequiredException
|
||||
*/
|
||||
private function checkLockRequirements(int $lockMode, ClassMetadata $class): void
|
||||
{
|
||||
switch ($lockMode) {
|
||||
case LockMode::OPTIMISTIC:
|
||||
if (!$class->isVersioned) {
|
||||
throw OptimisticLockException::notVersioned($class->name);
|
||||
}
|
||||
// Intentional fallthrough
|
||||
case LockMode::PESSIMISTIC_READ:
|
||||
case LockMode::PESSIMISTIC_WRITE:
|
||||
if (!$this->getConnection()->isTransactionActive()) {
|
||||
throw TransactionRequiredException::transactionRequired();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\Common\Util\Inflector;
|
||||
use Doctrine\Common\Inflector\Inflector;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
use Doctrine\Common\Persistence\ObjectRepository;
|
||||
use Doctrine\Common\Collections\Selectable;
|
||||
|
||||
@@ -27,7 +27,7 @@ abstract class AbstractIdGenerator
|
||||
* Generates an identifier for an entity.
|
||||
*
|
||||
* @param EntityManager $em
|
||||
* @param \Doctrine\ORM\Mapping\Entity $entity
|
||||
* @param object|null $entity
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function generate(EntityManager $em, $entity);
|
||||
|
||||
@@ -24,6 +24,8 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use PDO;
|
||||
use function array_map;
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* Base class for all hydrators. A hydrator is a class that provides some form
|
||||
@@ -296,11 +298,8 @@ abstract class AbstractHydrator
|
||||
|
||||
// If there are field name collisions in the child class, then we need
|
||||
// to only hydrate if we are looking at the correct discriminator value
|
||||
if(
|
||||
isset($cacheKeyInfo['discriminatorColumn']) &&
|
||||
isset($data[$cacheKeyInfo['discriminatorColumn']]) &&
|
||||
// Note: loose comparison required. See https://github.com/doctrine/doctrine2/pull/6304#issuecomment-323294442
|
||||
$data[$cacheKeyInfo['discriminatorColumn']] != $cacheKeyInfo['discriminatorValue']
|
||||
if (isset($cacheKeyInfo['discriminatorColumn'], $data[$cacheKeyInfo['discriminatorColumn']])
|
||||
&& ! in_array((string) $data[$cacheKeyInfo['discriminatorColumn']], $cacheKeyInfo['discriminatorValues'], true)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
@@ -401,7 +400,8 @@ abstract class AbstractHydrator
|
||||
$columnInfo,
|
||||
[
|
||||
'discriminatorColumn' => $this->_rsm->discriminatorColumns[$ownerMap],
|
||||
'discriminatorValue' => $classMetadata->discriminatorValue
|
||||
'discriminatorValue' => $classMetadata->discriminatorValue,
|
||||
'discriminatorValues' => $this->getDiscriminatorValues($classMetadata),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -454,6 +454,23 @@ abstract class AbstractHydrator
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getDiscriminatorValues(ClassMetadata $classMetadata) : array
|
||||
{
|
||||
$values = array_map(
|
||||
function (string $subClass) : string {
|
||||
return (string) $this->getClassMetadata($subClass)->discriminatorValue;
|
||||
},
|
||||
$classMetadata->subClasses
|
||||
);
|
||||
|
||||
$values[] = (string) $classMetadata->discriminatorValue;
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve ClassMetadata associated to entity class name.
|
||||
*
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\Common\Inflector\Inflector;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Common\Util\Inflector;
|
||||
use Doctrine\DBAL\Schema\AbstractSchemaManager;
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use Doctrine\DBAL\Schema\Table;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use SimpleXMLElement;
|
||||
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
|
||||
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
|
||||
@@ -429,7 +430,10 @@ class XmlDriver extends FileDriver
|
||||
if (isset($oneToManyElement->{'order-by'})) {
|
||||
$orderBy = [];
|
||||
foreach ($oneToManyElement->{'order-by'}->{'order-by-field'} as $orderByField) {
|
||||
$orderBy[(string) $orderByField['name']] = (string) $orderByField['direction'];
|
||||
$orderBy[(string) $orderByField['name']] = isset($orderByField['direction'])
|
||||
? (string) $orderByField['direction']
|
||||
: Criteria::ASC
|
||||
;
|
||||
}
|
||||
$mapping['orderBy'] = $orderBy;
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
foreach ($mapping['relationToSourceKeyColumns'] as $columnName => $refColumnName) {
|
||||
$params[] = isset($sourceClass->fieldNames[$refColumnName])
|
||||
? $identifier[$sourceClass->fieldNames[$refColumnName]]
|
||||
: $identifier[$sourceClass->getFieldForColumn($columnName)];
|
||||
: $identifier[$sourceClass->getFieldForColumn($refColumnName)];
|
||||
}
|
||||
|
||||
return $params;
|
||||
|
||||
@@ -37,6 +37,8 @@ use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\ORM\Utility\IdentifierFlattener;
|
||||
use Doctrine\ORM\Utility\PersisterHelper;
|
||||
use function array_merge;
|
||||
use function reset;
|
||||
|
||||
/**
|
||||
* A BasicEntityPersister maps an entity to a single table in a relational database.
|
||||
@@ -451,23 +453,21 @@ class BasicEntityPersister implements EntityPersister
|
||||
continue;
|
||||
}
|
||||
|
||||
$params[] = $identifier[$idField];
|
||||
$where[] = $this->class->associationMappings[$idField]['joinColumns'][0]['name'];
|
||||
$targetMapping = $this->em->getClassMetadata($this->class->associationMappings[$idField]['targetEntity']);
|
||||
$params[] = $identifier[$idField];
|
||||
$where[] = $this->quoteStrategy->getJoinColumnName(
|
||||
$this->class->associationMappings[$idField]['joinColumns'][0],
|
||||
$this->class,
|
||||
$this->platform
|
||||
);
|
||||
|
||||
switch (true) {
|
||||
case (isset($targetMapping->fieldMappings[$targetMapping->identifier[0]])):
|
||||
$types[] = $targetMapping->fieldMappings[$targetMapping->identifier[0]]['type'];
|
||||
break;
|
||||
$targetMapping = $this->em->getClassMetadata($this->class->associationMappings[$idField]['targetEntity']);
|
||||
$targetType = PersisterHelper::getTypeOfField($targetMapping->identifier[0], $targetMapping, $this->em);
|
||||
|
||||
case (isset($targetMapping->associationMappings[$targetMapping->identifier[0]])):
|
||||
$types[] = $targetMapping->associationMappings[$targetMapping->identifier[0]]['type'];
|
||||
break;
|
||||
|
||||
default:
|
||||
throw ORMException::unrecognizedField($targetMapping->identifier[0]);
|
||||
if ($targetType === []) {
|
||||
throw ORMException::unrecognizedField($targetMapping->identifier[0]);
|
||||
}
|
||||
|
||||
$types[] = reset($targetType);
|
||||
}
|
||||
|
||||
if ($versioned) {
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
use Doctrine\Common\Lexer\AbstractLexer;
|
||||
|
||||
/**
|
||||
* Scans a DQL query for tokens.
|
||||
*
|
||||
@@ -27,7 +29,7 @@ namespace Doctrine\ORM\Query;
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Lexer extends \Doctrine\Common\Lexer
|
||||
class Lexer extends AbstractLexer
|
||||
{
|
||||
// All tokens that are not valid identifiers must be < 100
|
||||
const T_NONE = 1;
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\AST\Functions;
|
||||
use function strpos;
|
||||
|
||||
/**
|
||||
* An LL(*) recursive-descent parser for the context-free grammar of the Doctrine Query Language.
|
||||
@@ -303,21 +304,24 @@ class Parser
|
||||
$lookaheadType = $this->lexer->lookahead['type'];
|
||||
|
||||
// Short-circuit on first condition, usually types match
|
||||
if ($lookaheadType !== $token) {
|
||||
// If parameter is not identifier (1-99) must be exact match
|
||||
if ($token < Lexer::T_IDENTIFIER) {
|
||||
$this->syntaxError($this->lexer->getLiteral($token));
|
||||
}
|
||||
if ($lookaheadType === $token) {
|
||||
$this->lexer->moveNext();
|
||||
return;
|
||||
}
|
||||
|
||||
// If parameter is keyword (200+) must be exact match
|
||||
if ($token > Lexer::T_IDENTIFIER) {
|
||||
$this->syntaxError($this->lexer->getLiteral($token));
|
||||
}
|
||||
// If parameter is not identifier (1-99) must be exact match
|
||||
if ($token < Lexer::T_IDENTIFIER) {
|
||||
$this->syntaxError($this->lexer->getLiteral($token));
|
||||
}
|
||||
|
||||
// If parameter is T_IDENTIFIER, then matches T_IDENTIFIER (100) and keywords (200+)
|
||||
if ($token === Lexer::T_IDENTIFIER && $lookaheadType < Lexer::T_IDENTIFIER) {
|
||||
$this->syntaxError($this->lexer->getLiteral($token));
|
||||
}
|
||||
// If parameter is keyword (200+) must be exact match
|
||||
if ($token > Lexer::T_IDENTIFIER) {
|
||||
$this->syntaxError($this->lexer->getLiteral($token));
|
||||
}
|
||||
|
||||
// If parameter is T_IDENTIFIER, then matches T_IDENTIFIER (100) and keywords (200+)
|
||||
if ($token === Lexer::T_IDENTIFIER && $lookaheadType < Lexer::T_IDENTIFIER) {
|
||||
$this->syntaxError($this->lexer->getLiteral($token));
|
||||
}
|
||||
|
||||
$this->lexer->moveNext();
|
||||
@@ -958,20 +962,20 @@ class Parser
|
||||
if ($this->lexer->isNextToken(Lexer::T_FULLY_QUALIFIED_NAME)) {
|
||||
$this->match(Lexer::T_FULLY_QUALIFIED_NAME);
|
||||
|
||||
$schemaName = $this->lexer->token['value'];
|
||||
} else if ($this->lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
|
||||
$schemaName = $this->lexer->token['value'];
|
||||
} else {
|
||||
$this->match(Lexer::T_ALIASED_NAME);
|
||||
|
||||
list($namespaceAlias, $simpleClassName) = explode(':', $this->lexer->token['value']);
|
||||
|
||||
$schemaName = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
|
||||
return $this->lexer->token['value'];
|
||||
}
|
||||
|
||||
return $schemaName;
|
||||
if ($this->lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
|
||||
return $this->lexer->token['value'];
|
||||
}
|
||||
|
||||
$this->match(Lexer::T_ALIASED_NAME);
|
||||
|
||||
[$namespaceAlias, $simpleClassName] = explode(':', $this->lexer->token['value']);
|
||||
|
||||
return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1280,7 +1284,9 @@ class Parser
|
||||
$this->match(Lexer::T_AS);
|
||||
}
|
||||
|
||||
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
|
||||
$aliasIdentificationVariable = $this->lexer->isNextToken(Lexer::T_IDENTIFIER)
|
||||
? $this->AliasIdentificationVariable()
|
||||
: 'alias_should_have_been_set';
|
||||
|
||||
$deleteClause->aliasIdentificationVariable = $aliasIdentificationVariable;
|
||||
$class = $this->em->getClassMetadata($deleteClause->abstractSchemaName);
|
||||
@@ -2918,6 +2924,10 @@ class Parser
|
||||
case Lexer::T_COALESCE:
|
||||
case Lexer::T_NULLIF:
|
||||
return $this->CaseExpression();
|
||||
default:
|
||||
if ($this->isAggregateFunction($lookaheadType)) {
|
||||
return $this->AggregateExpression();
|
||||
}
|
||||
}
|
||||
|
||||
$this->syntaxError(
|
||||
|
||||
@@ -181,9 +181,9 @@ class SchemaValidator
|
||||
|
||||
$identifierColumns = $targetMetadata->getIdentifierColumnNames();
|
||||
foreach ($assoc['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) {
|
||||
if (!in_array($inverseJoinColumn['referencedColumnName'], $identifierColumns)) {
|
||||
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' " .
|
||||
"has to be a primary key column on the target entity class '".$targetMetadata->name."'.";
|
||||
if (! in_array($inverseJoinColumn['referencedColumnName'], $identifierColumns)) {
|
||||
$ce[] = "The referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' " .
|
||||
"has to be a primary key column on the target entity class '" .$targetMetadata->name . "'.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,11 +171,11 @@ class Setup
|
||||
|
||||
|
||||
if (extension_loaded('memcached')) {
|
||||
$memcache = new \Memcached();
|
||||
$memcache->addServer('127.0.0.1', 11211);
|
||||
$memcached = new \Memcached();
|
||||
$memcached->addServer('127.0.0.1', 11211);
|
||||
|
||||
$cache = new \Doctrine\Common\Cache\MemcachedCache();
|
||||
$cache->setMemcache($memcache);
|
||||
$cache->setMemcached($memcached);
|
||||
|
||||
return $cache;
|
||||
}
|
||||
|
||||
@@ -940,7 +940,11 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$class->setIdentifierValues($entity, $idValue);
|
||||
}
|
||||
|
||||
$this->entityIdentifiers[$oid] = $idValue;
|
||||
// Some identifiers may be foreign keys to new entities.
|
||||
// In this case, we don't have the value yet and should treat it as if we have a post-insert generator
|
||||
if (! $this->hasMissingIdsWhichAreForeignKeys($class, $idValue)) {
|
||||
$this->entityIdentifiers[$oid] = $idValue;
|
||||
}
|
||||
}
|
||||
|
||||
$this->entityStates[$oid] = self::STATE_MANAGED;
|
||||
@@ -948,6 +952,20 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$this->scheduleForInsert($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $idValue
|
||||
*/
|
||||
private function hasMissingIdsWhichAreForeignKeys(ClassMetadata $class, array $idValue) : bool
|
||||
{
|
||||
foreach ($idValue as $idField => $idFieldValue) {
|
||||
if ($idFieldValue === null && isset($class->associationMappings[$idField])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL:
|
||||
* Computes the changeset of an individual entity, independently of the
|
||||
@@ -1033,12 +1051,16 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$persister = $this->getEntityPersister($className);
|
||||
$invoke = $this->listenersInvoker->getSubscribedSystems($class, Events::postPersist);
|
||||
|
||||
$insertionsForClass = [];
|
||||
|
||||
foreach ($this->entityInsertions as $oid => $entity) {
|
||||
|
||||
if ($this->em->getClassMetadata(get_class($entity))->name !== $className) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$insertionsForClass[$oid] = $entity;
|
||||
|
||||
$persister->addInsert($entity);
|
||||
|
||||
unset($this->entityInsertions[$oid]);
|
||||
@@ -1067,6 +1089,14 @@ class UnitOfWork implements PropertyChangedListener
|
||||
|
||||
$this->addToIdentityMap($entity);
|
||||
}
|
||||
} else {
|
||||
foreach ($insertionsForClass as $oid => $entity) {
|
||||
if (! isset($this->entityIdentifiers[$oid])) {
|
||||
//entity was not added to identity map because some identifiers are foreign keys to new entities.
|
||||
//add it now
|
||||
$this->addToEntityIdentifiersAndEntityMap($class, $oid, $entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
@@ -1074,6 +1104,30 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $entity
|
||||
*/
|
||||
private function addToEntityIdentifiersAndEntityMap(ClassMetadata $class, string $oid, $entity): void
|
||||
{
|
||||
$identifier = [];
|
||||
|
||||
foreach ($class->getIdentifierFieldNames() as $idField) {
|
||||
$value = $class->getFieldValue($entity, $idField);
|
||||
|
||||
if (isset($class->associationMappings[$idField])) {
|
||||
// NOTE: Single Columns as associated identifiers only allowed - this constraint it is enforced.
|
||||
$value = $this->getSingleIdentifierValue($value);
|
||||
}
|
||||
|
||||
$identifier[$idField] = $this->originalEntityData[$oid][$idField] = $value;
|
||||
}
|
||||
|
||||
$this->entityStates[$oid] = self::STATE_MANAGED;
|
||||
$this->entityIdentifiers[$oid] = $identifier;
|
||||
|
||||
$this->addToIdentityMap($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all entity updates for entities of the specified type.
|
||||
*
|
||||
|
||||
@@ -35,7 +35,7 @@ class Version
|
||||
/**
|
||||
* Current Doctrine Version
|
||||
*/
|
||||
const VERSION = '2.6.0';
|
||||
const VERSION = '2.6.2';
|
||||
|
||||
/**
|
||||
* Compares a Doctrine version with the current one.
|
||||
|
||||
15
tests/Doctrine/Tests/Models/GH7141/GH7141Article.php
Normal file
15
tests/Doctrine/Tests/Models/GH7141/GH7141Article.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\Models\GH7141;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
class GH7141Article
|
||||
{
|
||||
private $tags;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->tags = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\Models\ManyToManyPersister;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="manytomanypersister_child")
|
||||
*/
|
||||
class ChildClass
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(name="id1", type="integer")
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $id1;
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @ManyToOne(targetEntity=OtherParentClass::class, cascade={"persist"})
|
||||
* @JoinColumn(name="other_parent_id", referencedColumnName="id")
|
||||
*
|
||||
* @var OtherParentClass
|
||||
*/
|
||||
public $otherParent;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity=ParentClass::class, inversedBy="children")
|
||||
* @JoinTable(
|
||||
* name="parent_child",
|
||||
* joinColumns={
|
||||
* @JoinColumn(name="child_id1", referencedColumnName="id1"),
|
||||
* @JoinColumn(name="child_id2", referencedColumnName="other_parent_id")
|
||||
* },
|
||||
* inverseJoinColumns={@JoinColumn(name="parent_id", referencedColumnName="id")}
|
||||
* )
|
||||
*
|
||||
* @var Collection|ParentClass[]
|
||||
*/
|
||||
public $parents;
|
||||
|
||||
public function __construct(int $id1, OtherParentClass $otherParent)
|
||||
{
|
||||
$this->id1 = $id1;
|
||||
$this->otherParent = $otherParent;
|
||||
$this->parents = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\Models\ManyToManyPersister;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="manytomanypersister_other_parent")
|
||||
*/
|
||||
class OtherParentClass
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(name="id", type="integer")
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $id;
|
||||
|
||||
public function __construct(int $id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\Models\ManyToManyPersister;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Id;
|
||||
use Doctrine\ORM\Mapping\ManyToMany;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="manytomanypersister_parent")
|
||||
*/
|
||||
class ParentClass
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(name="id", type="integer")
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity=ChildClass::class, mappedBy="parents", orphanRemoval=true, cascade={"persist"})
|
||||
*
|
||||
* @var Collection|ChildClass[]
|
||||
*/
|
||||
public $children;
|
||||
|
||||
public function __construct(int $id)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->children = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Functional;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Doctrine\Tests\Models\Company\CompanyManager;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Functional Query tests.
|
||||
@@ -292,7 +293,7 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase
|
||||
*
|
||||
* @dataProvider dateAddSubProvider
|
||||
*/
|
||||
public function testDateAdd(string $unit, int $amount, int $expectedValue, int $delta = 0) : void
|
||||
public function testDateAdd(string $unit, int $amount, int $delta = 0) : void
|
||||
{
|
||||
$query = sprintf(
|
||||
'SELECT CURRENT_TIMESTAMP() as now, DATE_ADD(CURRENT_TIMESTAMP(), %d, \'%s\') AS add FROM %s m',
|
||||
@@ -308,9 +309,12 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase
|
||||
self::assertArrayHasKey('now', $result);
|
||||
self::assertArrayHasKey('add', $result);
|
||||
|
||||
$diff = strtotime($result['add']) - strtotime($result['now']);
|
||||
|
||||
self::assertEquals($expectedValue, $diff, '', $delta);
|
||||
self::assertEquals(
|
||||
(new \DateTimeImmutable($result['now']))->modify(sprintf('+%d %s', $amount, $unit)),
|
||||
new \DateTimeImmutable($result['add']),
|
||||
'',
|
||||
$delta
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,7 +323,7 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase
|
||||
*
|
||||
* @dataProvider dateAddSubProvider
|
||||
*/
|
||||
public function testDateSub(string $unit, int $amount, int $expectedValue, int $delta = 0) : void
|
||||
public function testDateSub(string $unit, int $amount, int $delta = 0) : void
|
||||
{
|
||||
$query = sprintf(
|
||||
'SELECT CURRENT_TIMESTAMP() as now, DATE_SUB(CURRENT_TIMESTAMP(), %d, \'%s\') AS sub FROM %s m',
|
||||
@@ -335,9 +339,12 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase
|
||||
self::assertArrayHasKey('now', $result);
|
||||
self::assertArrayHasKey('sub', $result);
|
||||
|
||||
$diff = strtotime($result['now']) - strtotime($result['sub']);
|
||||
|
||||
self::assertEquals($expectedValue, $diff, '', $delta);
|
||||
self::assertEquals(
|
||||
(new \DateTimeImmutable($result['now']))->modify(sprintf('-%d %s', $amount, $unit)),
|
||||
new \DateTimeImmutable($result['sub']),
|
||||
'',
|
||||
$delta
|
||||
);
|
||||
}
|
||||
|
||||
public function dateAddSubProvider() : array
|
||||
@@ -345,9 +352,10 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase
|
||||
$secondsInDay = 86400;
|
||||
|
||||
return [
|
||||
'year' => ['year', 1, 365 * $secondsInDay, 3 * $secondsInDay],
|
||||
'month' => ['month', 1, 30 * $secondsInDay, 2 * $secondsInDay],
|
||||
'week' => ['week', 1, 7 * $secondsInDay, $secondsInDay],
|
||||
'year' => ['year', 1, $secondsInDay],
|
||||
'month' => ['month', 1, $secondsInDay],
|
||||
'week' => ['week', 1, $secondsInDay],
|
||||
'day' => ['day', 2, $secondsInDay],
|
||||
'hour' => ['hour', 1, 3600],
|
||||
'minute' => ['minute', 1, 60],
|
||||
'second' => ['second', 10, 10],
|
||||
|
||||
190
tests/Doctrine/Tests/ORM/Functional/Ticket/GH6531Test.php
Normal file
190
tests/Doctrine/Tests/ORM/Functional/Ticket/GH6531Test.php
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
final class GH6531Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp() : void
|
||||
{
|
||||
parent::setup();
|
||||
|
||||
$this->setUpEntitySchema(
|
||||
[
|
||||
GH6531User::class,
|
||||
GH6531Address::class,
|
||||
GH6531Article::class,
|
||||
GH6531ArticleAttribute::class,
|
||||
GH6531Order::class,
|
||||
GH6531OrderItem::class,
|
||||
GH6531Product::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group 6531
|
||||
*/
|
||||
public function testSimpleDerivedIdentity() : void
|
||||
{
|
||||
$user = new GH6531User();
|
||||
$address = new GH6531Address();
|
||||
$address->user = $user;
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->persist($address);
|
||||
$this->_em->flush();
|
||||
|
||||
self::assertSame($user, $this->_em->find(GH6531User::class, $user->id));
|
||||
self::assertSame($address, $this->_em->find(GH6531Address::class, $user));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group 6531
|
||||
*/
|
||||
public function testDynamicAttributes() : void
|
||||
{
|
||||
$article = new GH6531Article();
|
||||
$article->addAttribute('name', 'value');
|
||||
|
||||
$this->_em->persist($article);
|
||||
$this->_em->flush();
|
||||
|
||||
self::assertSame(
|
||||
$article->attributes['name'],
|
||||
$this->_em->find(GH6531ArticleAttribute::class, ['article' => $article, 'attribute' => 'name'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group 6531
|
||||
*/
|
||||
public function testJoinTableWithMetadata() : void
|
||||
{
|
||||
$product = new GH6531Product();
|
||||
$this->_em->persist($product);
|
||||
$this->_em->flush();
|
||||
|
||||
$order = new GH6531Order();
|
||||
$order->addItem($product, 2);
|
||||
|
||||
$this->_em->persist($order);
|
||||
$this->_em->flush();
|
||||
|
||||
self::assertSame(
|
||||
$order->items->first(),
|
||||
$this->_em->find(GH6531OrderItem::class, ['product' => $product, 'order' => $order])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH6531User
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH6531Address
|
||||
{
|
||||
/** @Id @OneToOne(targetEntity=GH6531User::class) */
|
||||
public $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH6531Article
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @OneToMany(targetEntity=GH6531ArticleAttribute::class, mappedBy="article", cascade={"ALL"}, indexBy="attribute") */
|
||||
public $attributes;
|
||||
|
||||
public function addAttribute(string $name, string $value)
|
||||
{
|
||||
$this->attributes[$name] = new GH6531ArticleAttribute($name, $value, $this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH6531ArticleAttribute
|
||||
{
|
||||
/** @Id @ManyToOne(targetEntity=GH6531Article::class, inversedBy="attributes") */
|
||||
public $article;
|
||||
|
||||
/** @Id @Column(type="string") */
|
||||
public $attribute;
|
||||
|
||||
/** @Column(type="string") */
|
||||
public $value;
|
||||
|
||||
public function __construct(string $name, string $value, GH6531Article $article)
|
||||
{
|
||||
$this->attribute = $name;
|
||||
$this->value = $value;
|
||||
$this->article = $article;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH6531Order
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @OneToMany(targetEntity=GH6531OrderItem::class, mappedBy="order", cascade={"ALL"}) */
|
||||
public $items;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->items = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function addItem(GH6531Product $product, int $amount) : void
|
||||
{
|
||||
$this->items->add(new GH6531OrderItem($this, $product, $amount));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH6531Product
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH6531OrderItem
|
||||
{
|
||||
/** @Id @ManyToOne(targetEntity=GH6531Order::class) */
|
||||
public $order;
|
||||
|
||||
/** @Id @ManyToOne(targetEntity=GH6531Product::class) */
|
||||
public $product;
|
||||
|
||||
/** @Column(type="integer") */
|
||||
public $amount = 1;
|
||||
|
||||
public function __construct(GH6531Order $order, GH6531Product $product, int $amount = 1)
|
||||
{
|
||||
$this->order = $order;
|
||||
$this->product = $product;
|
||||
$this->amount = $amount;
|
||||
}
|
||||
}
|
||||
119
tests/Doctrine/Tests/ORM/Functional/Ticket/GH6937Test.php
Normal file
119
tests/Doctrine/Tests/ORM/Functional/Ticket/GH6937Test.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @group 6937
|
||||
*/
|
||||
final class GH6937Test extends OrmFunctionalTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema([GH6937Person::class, GH6937Employee::class, GH6937Manager::class]);
|
||||
}
|
||||
|
||||
public function testPhoneNumberIsPopulatedWithFind() : void
|
||||
{
|
||||
$manager = new GH6937Manager();
|
||||
$manager->name = 'Kevin';
|
||||
$manager->phoneNumber = '555-5555';
|
||||
$manager->department = 'Accounting';
|
||||
|
||||
$this->_em->persist($manager);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$persistedManager = $this->_em->find(GH6937Person::class, $manager->id);
|
||||
|
||||
self::assertSame('Kevin', $persistedManager->name);
|
||||
self::assertSame('555-5555', $persistedManager->phoneNumber);
|
||||
self::assertSame('Accounting', $persistedManager->department);
|
||||
}
|
||||
|
||||
public function testPhoneNumberIsPopulatedWithQueryBuilderUsingSimpleObjectHydrator() : void
|
||||
{
|
||||
$manager = new GH6937Manager();
|
||||
$manager->name = 'Kevin';
|
||||
$manager->phoneNumber = '555-5555';
|
||||
$manager->department = 'Accounting';
|
||||
|
||||
$this->_em->persist($manager);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$persistedManager = $this->_em->getRepository(GH6937Person::class)
|
||||
->createQueryBuilder('e')
|
||||
->where('e.id = :id')
|
||||
->setParameter('id', $manager->id)
|
||||
->getQuery()
|
||||
->getOneOrNullResult(AbstractQuery::HYDRATE_SIMPLEOBJECT);
|
||||
|
||||
self::assertSame('Kevin', $persistedManager->name);
|
||||
self::assertSame('555-5555', $persistedManager->phoneNumber);
|
||||
self::assertSame('Accounting', $persistedManager->department);
|
||||
}
|
||||
|
||||
public function testPhoneNumberIsPopulatedWithQueryBuilder() : void
|
||||
{
|
||||
$manager = new GH6937Manager();
|
||||
$manager->name = 'Kevin';
|
||||
$manager->phoneNumber = '555-5555';
|
||||
$manager->department = 'Accounting';
|
||||
|
||||
$this->_em->persist($manager);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$persistedManager = $this->_em->getRepository(GH6937Person::class)
|
||||
->createQueryBuilder('e')
|
||||
->where('e.id = :id')
|
||||
->setParameter('id', $manager->id)
|
||||
->getQuery()
|
||||
->getOneOrNullResult();
|
||||
|
||||
self::assertSame('Kevin', $persistedManager->name);
|
||||
self::assertSame('555-5555', $persistedManager->phoneNumber);
|
||||
self::assertSame('Accounting', $persistedManager->department);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("JOINED")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"employee"=GH6937Employee::class, "manager"=GH6937Manager::class})
|
||||
*/
|
||||
abstract class GH6937Person
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @Column(type="string") */
|
||||
public $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
abstract class GH6937Employee extends GH6937Person
|
||||
{
|
||||
/** @Column(type="string") */
|
||||
public $phoneNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH6937Manager extends GH6937Employee
|
||||
{
|
||||
/** @Column(type="string") */
|
||||
public $department;
|
||||
}
|
||||
82
tests/Doctrine/Tests/ORM/Functional/Ticket/GH7012Test.php
Normal file
82
tests/Doctrine/Tests/ORM/Functional/Ticket/GH7012Test.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Tests\Models\Quote\User as QuotedUser;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
final class GH7012Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->useModelSet('quote');
|
||||
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema([GH7012UserData::class]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group 7012
|
||||
*/
|
||||
public function testUpdateEntityWithIdentifierAssociationWithQuotedJoinColumn() : void
|
||||
{
|
||||
$user = new QuotedUser();
|
||||
$user->name = 'John Doe';
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$userData = new GH7012UserData($user, '123456789');
|
||||
|
||||
$this->_em->persist($userData);
|
||||
$this->_em->flush();
|
||||
|
||||
$userData->name = '4321';
|
||||
$this->_em->flush();
|
||||
|
||||
$platform = $this->_em->getConnection()->getDatabasePlatform();
|
||||
$quotedTableName = $platform->quoteIdentifier('quote-user-data');
|
||||
$quotedColumn = $platform->quoteIdentifier('name');
|
||||
$quotedIdentifier = $platform->quoteIdentifier('user-id');
|
||||
|
||||
self::assertNotEquals('quote-user-data', $quotedTableName);
|
||||
self::assertNotEquals('name', $quotedColumn);
|
||||
self::assertNotEquals('user-id', $quotedIdentifier);
|
||||
|
||||
$queries = $this->_sqlLoggerStack->queries;
|
||||
|
||||
$this->assertSQLEquals(
|
||||
sprintf('UPDATE %s SET %s = ? WHERE %s = ?', $quotedTableName, $quotedColumn, $quotedIdentifier),
|
||||
$queries[$this->_sqlLoggerStack->currentQuery - 1]['sql']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="`quote-user-data`")
|
||||
*/
|
||||
class GH7012UserData
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @OneToOne(targetEntity=Doctrine\Tests\Models\Quote\User::class)
|
||||
* @JoinColumn(name="`user-id`", referencedColumnName="`user-id`", onDelete="CASCADE")
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* @Column(type="string", name="`name`")
|
||||
*/
|
||||
public $name;
|
||||
|
||||
public function __construct(QuotedUser $user, string $name)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
212
tests/Doctrine/Tests/ORM/Functional/Ticket/GH7062Test.php
Normal file
212
tests/Doctrine/Tests/ORM/Functional/Ticket/GH7062Test.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
class GH7062Test extends OrmFunctionalTestCase
|
||||
{
|
||||
private const SEASON_ID = 'season_18';
|
||||
private const TEAM_ID = 'team_A';
|
||||
|
||||
protected function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema(
|
||||
[
|
||||
GH7062Team::class,
|
||||
GH7062Season::class,
|
||||
GH7062Ranking::class,
|
||||
GH7062RankingPosition::class
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group 7062
|
||||
*/
|
||||
public function testEntityWithAssociationKeyIdentityCanBeUpdated() : void
|
||||
{
|
||||
$this->createInitialRankingWithRelatedEntities();
|
||||
$this->modifyRanking();
|
||||
$this->verifyRanking();
|
||||
}
|
||||
|
||||
private function createInitialRankingWithRelatedEntities() : void
|
||||
{
|
||||
$team = new GH7062Team(self::TEAM_ID);
|
||||
$season = new GH7062Season(self::SEASON_ID);
|
||||
|
||||
$season->ranking = new GH7062Ranking($season, [$team]);
|
||||
|
||||
$this->_em->persist($team);
|
||||
$this->_em->persist($season);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
foreach ($season->ranking->positions as $position) {
|
||||
self::assertSame(0, $position->points);
|
||||
}
|
||||
}
|
||||
|
||||
private function modifyRanking() : void
|
||||
{
|
||||
/** @var GH7062Ranking $ranking */
|
||||
$ranking = $this->_em->find(GH7062Ranking::class, self::SEASON_ID);
|
||||
|
||||
foreach ($ranking->positions as $position) {
|
||||
$position->points += 3;
|
||||
}
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
}
|
||||
|
||||
private function verifyRanking() : void
|
||||
{
|
||||
/** @var GH7062Season $season */
|
||||
$season = $this->_em->find(GH7062Season::class, self::SEASON_ID);
|
||||
self::assertInstanceOf(GH7062Season::class, $season);
|
||||
|
||||
$ranking = $season->ranking;
|
||||
self::assertInstanceOf(GH7062Ranking::class, $ranking);
|
||||
|
||||
foreach ($ranking->positions as $position) {
|
||||
self::assertSame(3, $position->points);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple Entity whose identity is defined through another Entity (Season)
|
||||
*
|
||||
* @Entity
|
||||
* @Table(name="soccer_rankings")
|
||||
*/
|
||||
class GH7062Ranking
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @OneToOne(targetEntity=GH7062Season::class, inversedBy="ranking")
|
||||
* @JoinColumn(name="season", referencedColumnName="id")
|
||||
*
|
||||
* @var GH7062Season
|
||||
*/
|
||||
public $season;
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity=GH7062RankingPosition::class, mappedBy="ranking", cascade={"all"})
|
||||
*
|
||||
* @var Collection|GH7062RankingPosition[]
|
||||
*/
|
||||
public $positions;
|
||||
|
||||
/**
|
||||
* @param GH7062Team[] $teams
|
||||
*/
|
||||
public function __construct(GH7062Season $season, array $teams)
|
||||
{
|
||||
$this->season = $season;
|
||||
$this->positions = new ArrayCollection();
|
||||
|
||||
foreach ($teams as $team) {
|
||||
$this->positions[] = new GH7062RankingPosition($this, $team);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entity which serves as a identity provider for other entities
|
||||
*
|
||||
* @Entity
|
||||
* @Table(name="soccer_seasons")
|
||||
*/
|
||||
class GH7062Season
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="string")
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @OneToOne(targetEntity=GH7062Ranking::class, mappedBy="season", cascade={"all"})
|
||||
*
|
||||
* @var GH7062Ranking|null
|
||||
*/
|
||||
public $ranking;
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entity which serves as a identity provider for other entities
|
||||
*
|
||||
* @Entity
|
||||
* @Table(name="soccer_teams")
|
||||
*/
|
||||
class GH7062Team
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="string")
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entity whose identity is defined through two other entities
|
||||
*
|
||||
* @Entity
|
||||
* @Table(name="soccer_ranking_positions")
|
||||
*/
|
||||
class GH7062RankingPosition
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @ManyToOne(targetEntity=GH7062Ranking::class, inversedBy="positions")
|
||||
* @JoinColumn(name="season", referencedColumnName="season")
|
||||
*
|
||||
* @var GH7062Ranking
|
||||
*/
|
||||
public $ranking;
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @ManyToOne(targetEntity=GH7062Team::class)
|
||||
* @JoinColumn(name="team_id", referencedColumnName="id")
|
||||
*
|
||||
* @var GH7062Team
|
||||
*/
|
||||
public $team;
|
||||
|
||||
/**
|
||||
* @Column(type="integer")
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $points;
|
||||
|
||||
public function __construct(GH7062Ranking $ranking, GH7062Team $team)
|
||||
{
|
||||
$this->ranking = $ranking;
|
||||
$this->team = $team;
|
||||
$this->points = 0;
|
||||
}
|
||||
}
|
||||
69
tests/Doctrine/Tests/ORM/Functional/Ticket/GH7067Test.php
Normal file
69
tests/Doctrine/Tests/ORM/Functional/Ticket/GH7067Test.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
final class GH7067Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp() : void
|
||||
{
|
||||
$this->enableSecondLevelCache();
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema([GH7067Entity::class]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group 7067
|
||||
*/
|
||||
public function testSLCWithVersion() : void
|
||||
{
|
||||
$entity = new GH7067Entity();
|
||||
$entity->lastUpdate = new \DateTime();
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
/** @var GH7067Entity $notCached */
|
||||
$notCached = $this->_em->find(GH7067Entity::class, $entity->id);
|
||||
|
||||
self::assertNotNull($notCached->version, 'Version already cached by persister above, it must be not null');
|
||||
|
||||
$notCached->lastUpdate = new \DateTime('+1 seconds');
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity()
|
||||
* @Cache(usage="NONSTRICT_READ_WRITE")
|
||||
*/
|
||||
class GH7067Entity
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @Column(type="datetime")
|
||||
*
|
||||
* @var \DateTime
|
||||
*/
|
||||
public $lastUpdate;
|
||||
|
||||
/**
|
||||
* @Column(type="datetime")
|
||||
* @Version
|
||||
*
|
||||
* @var \DateTime
|
||||
*/
|
||||
public $version;
|
||||
}
|
||||
43
tests/Doctrine/Tests/ORM/Functional/Ticket/GH7068Test.php
Normal file
43
tests/Doctrine/Tests/ORM/Functional/Ticket/GH7068Test.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\TransactionRequiredException;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
final class GH7068Test extends OrmFunctionalTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema(
|
||||
[
|
||||
SomeEntity::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function testLockModeIsRespected()
|
||||
{
|
||||
$entity = new SomeEntity();
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$this->_em->find(SomeEntity::class, 1);
|
||||
|
||||
$this->expectException(TransactionRequiredException::class);
|
||||
$this->_em->find(SomeEntity::class, 1, LockMode::PESSIMISTIC_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
final class SomeEntity {
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
}
|
||||
135
tests/Doctrine/Tests/ORM/Functional/Ticket/GH7286Test.php
Normal file
135
tests/Doctrine/Tests/ORM/Functional/Ticket/GH7286Test.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
final class GH7286Test extends OrmFunctionalTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema(
|
||||
[
|
||||
GH7286Entity::class,
|
||||
]
|
||||
);
|
||||
|
||||
$this->_em->persist(new GH7286Entity('foo', 1));
|
||||
$this->_em->persist(new GH7286Entity('foo', 2));
|
||||
$this->_em->persist(new GH7286Entity('bar', 3));
|
||||
$this->_em->persist(new GH7286Entity(null, 4));
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
}
|
||||
|
||||
public function testAggregateExpressionInFunction() : void
|
||||
{
|
||||
$query = $this->_em->createQuery(
|
||||
'SELECT CONCAT(e.type, MIN(e.version)) pair'
|
||||
. ' FROM ' . GH7286Entity::class . ' e'
|
||||
. ' WHERE e.type IS NOT NULL'
|
||||
. ' GROUP BY e.type'
|
||||
. ' ORDER BY e.type'
|
||||
);
|
||||
|
||||
self::assertSame(
|
||||
[
|
||||
['pair' => 'bar3'],
|
||||
['pair' => 'foo1'],
|
||||
],
|
||||
$query->getArrayResult()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-1091
|
||||
*/
|
||||
public function testAggregateFunctionInCustomFunction() : void
|
||||
{
|
||||
$this->_em->getConfiguration()->addCustomStringFunction('CC', GH7286CustomConcat::class);
|
||||
|
||||
$query = $this->_em->createQuery(
|
||||
'SELECT CC(e.type, MIN(e.version)) pair'
|
||||
. ' FROM ' . GH7286Entity::class . ' e'
|
||||
. ' WHERE e.type IS NOT NULL AND e.type != :type'
|
||||
. ' GROUP BY e.type'
|
||||
);
|
||||
$query->setParameter('type', 'bar');
|
||||
|
||||
self::assertSame(
|
||||
['pair' => 'foo1'],
|
||||
$query->getSingleResult()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7286Entity
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @Column(nullable=true)
|
||||
* @var string|null
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* @Column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
public $version;
|
||||
|
||||
public function __construct(?string $type, int $version)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->version = $version;
|
||||
}
|
||||
}
|
||||
|
||||
class GH7286CustomConcat extends FunctionNode
|
||||
{
|
||||
/** @var Node */
|
||||
private $first;
|
||||
|
||||
/** @var Node */
|
||||
private $second;
|
||||
|
||||
public function parse(Parser $parser) : void
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->first = $parser->StringPrimary();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$this->second = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
|
||||
public function getSql(SqlWalker $walker) : string
|
||||
{
|
||||
return $walker->getConnection()->getDatabasePlatform()->getConcatExpression(
|
||||
$this->first->dispatch($walker),
|
||||
$this->second->dispatch($walker)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Mapping;
|
||||
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Persistence\Mapping\RuntimeReflectionService;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
@@ -11,6 +12,7 @@ use Doctrine\Tests\Models\DDC3293\DDC3293User;
|
||||
use Doctrine\Tests\Models\DDC3293\DDC3293UserPrefixed;
|
||||
use Doctrine\Tests\Models\DDC889\DDC889Class;
|
||||
use Doctrine\Tests\Models\Generic\SerializationModel;
|
||||
use Doctrine\Tests\Models\GH7141\GH7141Article;
|
||||
use Doctrine\Tests\Models\ValueObjects\Name;
|
||||
use Doctrine\Tests\Models\ValueObjects\Person;
|
||||
|
||||
@@ -174,6 +176,24 @@ class XmlMappingDriverTest extends AbstractMappingDriverTest
|
||||
}, $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group GH-7141
|
||||
*/
|
||||
public function testOneToManyDefaultOrderByAsc()
|
||||
{
|
||||
$driver = $this->_loadDriver();
|
||||
$class = new ClassMetadata(GH7141Article::class);
|
||||
|
||||
$class->initializeReflection(new RuntimeReflectionService());
|
||||
$driver->loadMetadataForClass(GH7141Article::class, $class);
|
||||
|
||||
|
||||
$this->assertEquals(
|
||||
Criteria::ASC,
|
||||
$class->getMetadataValue('associationMappings')['tags']['orderBy']['position']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-889
|
||||
* @expectedException \Doctrine\Common\Persistence\Mapping\MappingException
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?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://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\GH7141\GH7141Article">
|
||||
<one-to-many field="tags" target-entity="NoTargetEntity" mapped-by="noMappedByField">
|
||||
<order-by>
|
||||
<order-by-field name="position"/>
|
||||
</order-by>
|
||||
</one-to-many>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Persisters;
|
||||
|
||||
use Doctrine\ORM\Persisters\Collection\ManyToManyPersister;
|
||||
use Doctrine\Tests\Mocks\ConnectionMock;
|
||||
use Doctrine\Tests\Models\ManyToManyPersister\ChildClass;
|
||||
use Doctrine\Tests\Models\ManyToManyPersister\OtherParentClass;
|
||||
use Doctrine\Tests\Models\ManyToManyPersister\ParentClass;
|
||||
use Doctrine\Tests\OrmTestCase;
|
||||
|
||||
/**
|
||||
* @covers \Doctrine\ORM\Persisters\Collection\ManyToManyPersister
|
||||
*/
|
||||
final class ManyToManyPersisterTest extends OrmTestCase
|
||||
{
|
||||
/**
|
||||
* @group 6991
|
||||
* @group ManyToManyPersister
|
||||
*
|
||||
* @throws \Doctrine\ORM\ORMException
|
||||
*/
|
||||
public function testDeleteManyToManyCollection(): void
|
||||
{
|
||||
$parent = new ParentClass(1);
|
||||
$otherParent = new OtherParentClass(42);
|
||||
$child = new ChildClass(1, $otherParent);
|
||||
|
||||
$parent->children->add($child);
|
||||
$child->parents->add($parent);
|
||||
|
||||
$em = $this->_getTestEntityManager();
|
||||
$em->persist($parent);
|
||||
$em->flush();
|
||||
|
||||
/** @var ChildClass|null $childReloaded */
|
||||
$childReloaded = $em->find(ChildClass::class, ['id1' => 1, 'otherParent' => $otherParent]);
|
||||
|
||||
self::assertNotNull($childReloaded);
|
||||
|
||||
$persister = new ManyToManyPersister($em);
|
||||
$persister->delete($childReloaded->parents);
|
||||
|
||||
/** @var ConnectionMock $conn */
|
||||
$conn = $em->getConnection();
|
||||
|
||||
$updates = $conn->getExecuteUpdates();
|
||||
$lastUpdate = array_pop($updates);
|
||||
|
||||
self::assertEquals('DELETE FROM parent_child WHERE child_id1 = ? AND child_id2 = ?', $lastUpdate['query']);
|
||||
self::assertEquals([1, 42], $lastUpdate['params']);
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,17 @@ class DeleteSqlGenerationTest extends OrmTestCase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group 6939
|
||||
*/
|
||||
public function testSupportsDeleteWithoutWhereAndAlias() : void
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
'DELETE FROM Doctrine\Tests\Models\CMS\CmsUser',
|
||||
'DELETE FROM cms_users'
|
||||
);
|
||||
}
|
||||
|
||||
public function testSupportsDeleteWithoutWhereAndFrom()
|
||||
{
|
||||
$this->assertSqlGeneration(
|
||||
|
||||
@@ -708,6 +708,13 @@ class LanguageRecognitionTest extends OrmTestCase
|
||||
{
|
||||
$this->assertValidDQL("SELECT new " . __NAMESPACE__ . "\\DummyStruct(u.id, 'foo', (SELECT 1 FROM Doctrine\Tests\Models\CMS\CmsUser su), true) FROM Doctrine\Tests\Models\CMS\CmsUser u");
|
||||
}
|
||||
|
||||
public function testStringPrimaryAcceptsAggregateExpression() : void
|
||||
{
|
||||
$this->assertValidDQL(
|
||||
'SELECT CONCAT(a.topic, MAX(a.version)) last FROM Doctrine\Tests\Models\CMS\CmsArticle a GROUP BY a'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
|
||||
@@ -823,7 +823,14 @@ class SelectSqlGenerationTest extends OrmTestCase
|
||||
->setMaxResults(10)
|
||||
->setFirstResult(0);
|
||||
|
||||
$this->assertEquals('SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c0_.email_id AS email_id_4 FROM cms_users c0_ LIMIT 10 OFFSET 0', $q->getSql());
|
||||
// DBAL 2.8+ doesn't add OFFSET part when offset is 0
|
||||
self::assertThat(
|
||||
$q->getSql(),
|
||||
self::logicalOr(
|
||||
self::identicalTo('SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c0_.email_id AS email_id_4 FROM cms_users c0_ LIMIT 10'),
|
||||
self::identicalTo('SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c0_.email_id AS email_id_4 FROM cms_users c0_ LIMIT 10 OFFSET 0')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function testSizeFunction()
|
||||
|
||||
Reference in New Issue
Block a user