mirror of
https://github.com/doctrine/orm.git
synced 2026-04-24 06:58:19 +02:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 16751d210f | |||
| 686f508576 | |||
| 00ef1eba90 | |||
| 3843eee5cb | |||
| 6a827d5b61 | |||
| 7d77984306 | |||
| ec93014713 | |||
| c83094bde0 | |||
| 982d1519db | |||
| 855244fd10 | |||
| c62977412c | |||
| 98e557b68e | |||
| 1dde2c9e8e | |||
| adfd010a78 | |||
| 1bc4e1f594 | |||
| 21680df9bd | |||
| 19aa3c125c | |||
| e9e012a037 | |||
| d1db0655ac | |||
| 9fef4e86e4 | |||
| 4781dc03e9 | |||
| cc5f84ac22 | |||
| 023e94661a | |||
| b59fc23f86 | |||
| d71dd5d94f | |||
| 63513e9a05 | |||
| c802bc46a5 | |||
| 506bf0ee12 | |||
| a36809db72 | |||
| 5b00d7ba5e | |||
| b22604352d | |||
| 00c6b1bc60 | |||
| 4b0d86ee92 | |||
| 3707c39124 | |||
| fe72b00df2 | |||
| 79a7ecc92f | |||
| 16df8bfe0d | |||
| b37ceaa9f7 | |||
| c41fdbce8a | |||
| 7526adc80a | |||
| 766eb693fb | |||
| f9e2ae3488 | |||
| 6bf2ff5d10 | |||
| 27fcc01d81 | |||
| 3ac1f8e680 | |||
| b63db53552 | |||
| bed8186573 | |||
| f08ff83d0a | |||
| 7c8c0906be | |||
| 167cb44ea1 | |||
| 5d74bdb240 | |||
| ca38249f6c | |||
| 6a74f373b9 | |||
| 1c45e1b744 | |||
| 5612790307 | |||
| 17bc627bf2 |
@@ -249,7 +249,7 @@ Example usage
|
||||
$em->clear();
|
||||
|
||||
// Fetch the Location object
|
||||
$query = $em->createQuery("SELECT l FROM Geo\Entity\Location WHERE l.address = '1600 Amphitheatre Parkway, Mountain View, CA'");
|
||||
$query = $em->createQuery("SELECT l FROM Geo\Entity\Location l WHERE l.address = '1600 Amphitheatre Parkway, Mountain View, CA'");
|
||||
$location = $query->getSingleResult();
|
||||
|
||||
/* @var Geo\ValueObject\Point */
|
||||
|
||||
@@ -90,7 +90,10 @@ the UTC time at the time of the booking and the timezone the event happened in.
|
||||
|
||||
class UTCDateTimeType extends DateTimeType
|
||||
{
|
||||
static private $utc;
|
||||
/**
|
||||
* @var \DateTimeZone
|
||||
*/
|
||||
private static $utc;
|
||||
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -110,7 +113,7 @@ the UTC time at the time of the booking and the timezone the event happened in.
|
||||
$converted = \DateTime::createFromFormat(
|
||||
$platform->getDateTimeFormatString(),
|
||||
$value,
|
||||
self::$utc ? self::$utc : self::$utc = new \DateTimeZone('UTC')
|
||||
self::getUtc()
|
||||
);
|
||||
|
||||
if (! $converted) {
|
||||
@@ -123,6 +126,11 @@ the UTC time at the time of the booking and the timezone the event happened in.
|
||||
|
||||
return $converted;
|
||||
}
|
||||
|
||||
private static function getUtc(): \DateTimeZone
|
||||
{
|
||||
return self::$utc ?: self::$utc = new \DateTimeZone('UTC');
|
||||
}
|
||||
}
|
||||
|
||||
This database type makes sure that every DateTime instance is always saved in UTC, relative
|
||||
|
||||
@@ -286,7 +286,7 @@ below.
|
||||
// ...
|
||||
|
||||
/**
|
||||
* One Student has One Student.
|
||||
* One Student has One Mentor.
|
||||
* @OneToOne(targetEntity="Student")
|
||||
* @JoinColumn(name="mentor_id", referencedColumnName="id")
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,15 @@ especially what the strategies presented here provide help with.
|
||||
operations.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Having an SQL logger enabled when processing batches can have a serious impact on performance and resource usage.
|
||||
To avoid that you should disable it in the DBAL configuration:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$em->getConnection()->getConfiguration()->setSQLLogger(null);
|
||||
|
||||
Bulk Inserts
|
||||
------------
|
||||
|
||||
@@ -75,7 +84,7 @@ with the batching strategy that was already used for bulk inserts:
|
||||
|
||||
<?php
|
||||
$batchSize = 20;
|
||||
$i = 0;
|
||||
$i = 1;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
$iterableResult = $q->iterate();
|
||||
foreach ($iterableResult as $row) {
|
||||
@@ -136,7 +145,7 @@ The following example shows how to do this:
|
||||
|
||||
<?php
|
||||
$batchSize = 20;
|
||||
$i = 0;
|
||||
$i = 1;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
$iterableResult = $q->iterate();
|
||||
while (($row = $iterableResult->next()) !== false) {
|
||||
|
||||
@@ -996,8 +996,9 @@ the Query class. Here they are:
|
||||
result contains more than one object, an ``NonUniqueResultException``
|
||||
is thrown. If the result contains no objects, an ``NoResultException``
|
||||
is thrown. The pure/mixed distinction does not apply.
|
||||
- ``Query#getOneOrNullResult()``: Retrieve a single object. If no
|
||||
object is found null will be returned.
|
||||
- ``Query#getOneOrNullResult()``: Retrieve a single object. If the
|
||||
result contains more than one object, a ``NonUniqueResultException``
|
||||
is thrown. If no object is found null will be returned.
|
||||
- ``Query#getArrayResult()``: Retrieves an array graph (a nested
|
||||
array) that is largely interchangeable with the object graph
|
||||
generated by ``Query#getResult()`` for read-only purposes.
|
||||
|
||||
@@ -198,6 +198,21 @@ No, it is not supported to sort by function in DQL. If you need this functionali
|
||||
use a native-query or come up with another solution. As a side note: Sorting with ORDER BY RAND() is painfully slow
|
||||
starting with 1000 rows.
|
||||
|
||||
Is it better to write DQL or to generate it with the query builder?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The purpose of the ``QueryBuilder`` is to generate DQL dynamically,
|
||||
which is useful when you have optional filters, conditional joins, etc.
|
||||
|
||||
But the ``QueryBuilder`` is not an alternative to DQL, it actually generates DQL
|
||||
queries at runtime, which are then interpreted by Doctrine. This means that
|
||||
using the ``QueryBuilder`` to build and run a query is actually always slower
|
||||
than only running the corresponding DQL query.
|
||||
|
||||
So if you only need to generate a query and bind parameters to it,
|
||||
you should use plain DQL, as this is a simpler and much more readable solution.
|
||||
You should only use the ``QueryBuilder`` when you can't achieve what you want to do with a DQL query.
|
||||
|
||||
A Query fails, how can I debug it?
|
||||
----------------------------------
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ proper quoting of parameters.
|
||||
|
||||
<?php
|
||||
namespace Example;
|
||||
use Doctrine\ORM\Mapping\ClassMetaData,
|
||||
use Doctrine\ORM\Mapping\ClassMetadata,
|
||||
Doctrine\ORM\Query\Filter\SQLFilter;
|
||||
|
||||
class MyLocaleFilter extends SQLFilter
|
||||
|
||||
@@ -9,6 +9,12 @@ programmatically build queries, and also provides a fluent API.
|
||||
This means that you can change between one methodology to the other
|
||||
as you want, or just pick a preferred one.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``QueryBuilder`` is not an abstraction of DQL, but merely a tool to dynamically build it.
|
||||
You should still use plain DQL when you can, as it is simpler and more readable.
|
||||
More about this in the :doc:`FAQ <faq>`_.
|
||||
|
||||
Constructing a new QueryBuilder object
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -80,7 +86,7 @@ Working with QueryBuilder
|
||||
High level API methods
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To simplify even more the way you build a query in Doctrine, you can take
|
||||
The most straightforward way to build a dynamic query with the ``QueryBuilder`` is by taking
|
||||
advantage of Helper methods. For all base code, there is a set of
|
||||
useful methods to simplify a programmer's life. To illustrate how
|
||||
to work with them, here is the same example 6 re-written using
|
||||
@@ -97,10 +103,9 @@ to work with them, here is the same example 6 re-written using
|
||||
->orderBy('u.name', 'ASC');
|
||||
|
||||
``QueryBuilder`` helper methods are considered the standard way to
|
||||
build DQL queries. Although it is supported, using string-based
|
||||
queries should be avoided. You are greatly encouraged to use
|
||||
``$qb->expr()->*`` methods. Here is a converted example 8 to
|
||||
suggested standard way to build queries:
|
||||
use the ``QueryBuilder``. The ``$qb->expr()->*`` methods can help you
|
||||
build conditional expressions dynamically. Here is a converted example 8 to
|
||||
suggested way to build queries with dynamic conditions:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
|
||||
@@ -252,15 +252,6 @@ will output the SQL for the ran operation.
|
||||
Before using the orm:schema-tool commands, remember to configure
|
||||
your cli-config.php properly.
|
||||
|
||||
.. note::
|
||||
|
||||
When using the Annotation Mapping Driver you have to either setup
|
||||
your autoloader in the cli-config.php correctly to find all the
|
||||
entities, or you can use the second argument of the
|
||||
``EntityManagerHelper`` to specify all the paths of your entities
|
||||
(or mapping files), i.e.
|
||||
``new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em, $mappingPaths);``
|
||||
|
||||
Entity Generation
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ wishes to be hydrated. Default result-types include:
|
||||
- SQL to simple scalar result arrays
|
||||
- SQL to a single result variable
|
||||
|
||||
Hydration to entities and arrays is one of most complex parts of Doctrine
|
||||
Hydration to entities and arrays is one of the most complex parts of Doctrine
|
||||
algorithm-wise. It can build results with for example:
|
||||
|
||||
- Single table selects
|
||||
|
||||
@@ -800,7 +800,9 @@ DQL and its syntax as well as the Doctrine class can be found in
|
||||
:doc:`the dedicated chapter <dql-doctrine-query-language>`.
|
||||
For programmatically building up queries based on conditions that
|
||||
are only known at runtime, Doctrine provides the special
|
||||
``Doctrine\ORM\QueryBuilder`` class. More information on
|
||||
``Doctrine\ORM\QueryBuilder`` class. While this a powerful tool,
|
||||
it also brings more complexity to your code compared to plain DQL,
|
||||
so you should only use it when you need it. More information on
|
||||
constructing queries with a QueryBuilder can be found
|
||||
:doc:`in Query Builder chapter <query-builder>`.
|
||||
|
||||
|
||||
@@ -1210,8 +1210,7 @@ The console output of this script is then:
|
||||
throw your ORM into the dumpster, because it doesn't support some
|
||||
the more powerful SQL concepts.
|
||||
|
||||
|
||||
Instead of handwriting DQL you can use the ``QueryBuilder`` retrieved
|
||||
If you need to build your query dynamically, you can use the ``QueryBuilder`` retrieved
|
||||
by calling ``$entityManager->createQueryBuilder()``. There are more
|
||||
details about this in the relevant part of the documentation.
|
||||
|
||||
|
||||
@@ -822,8 +822,9 @@ abstract class AbstractQuery
|
||||
*
|
||||
* Alias for getSingleResult(HYDRATE_SINGLE_SCALAR).
|
||||
*
|
||||
* @return mixed The scalar result, or NULL if the query returned no result.
|
||||
* @return mixed The scalar result.
|
||||
*
|
||||
* @throws NoResultException If the query returned no result.
|
||||
* @throws NonUniqueResultException If the query result is not unique.
|
||||
*/
|
||||
public function getSingleScalarResult()
|
||||
|
||||
@@ -23,6 +23,7 @@ use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker;
|
||||
use PDO;
|
||||
use function array_map;
|
||||
use function in_array;
|
||||
@@ -351,13 +352,11 @@ abstract class AbstractHydrator
|
||||
|
||||
// WARNING: BC break! We know this is the desired behavior to type convert values, but this
|
||||
// erroneous behavior exists since 2.0 and we're forced to keep compatibility.
|
||||
if ( ! isset($cacheKeyInfo['isScalar'])) {
|
||||
$dqlAlias = $cacheKeyInfo['dqlAlias'];
|
||||
$type = $cacheKeyInfo['type'];
|
||||
$fieldName = $dqlAlias . '_' . $fieldName;
|
||||
$value = $type
|
||||
? $type->convertToPHPValue($value, $this->_platform)
|
||||
: $value;
|
||||
if (! isset($cacheKeyInfo['isScalar'])) {
|
||||
$type = $cacheKeyInfo['type'];
|
||||
$value = $type ? $type->convertToPHPValue($value, $this->_platform) : $value;
|
||||
|
||||
$fieldName = $cacheKeyInfo['dqlAlias'] . '_' . $fieldName;
|
||||
}
|
||||
|
||||
$rowData[$fieldName] = $value;
|
||||
@@ -422,6 +421,12 @@ abstract class AbstractHydrator
|
||||
'class' => new \ReflectionClass($mapping['className']),
|
||||
];
|
||||
|
||||
case isset($this->_rsm->scalarMappings[$key], $this->_hints[LimitSubqueryWalker::FORCE_DBAL_TYPE_CONVERSION]):
|
||||
return $this->_cache[$key] = [
|
||||
'fieldName' => $this->_rsm->scalarMappings[$key],
|
||||
'type' => Type::getType($this->_rsm->typeMappings[$key]),
|
||||
'dqlAlias' => '',
|
||||
];
|
||||
case (isset($this->_rsm->scalarMappings[$key])):
|
||||
return $this->_cache[$key] = [
|
||||
'isScalar' => true,
|
||||
|
||||
@@ -422,7 +422,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$this->resultPointers[$dqlAlias] = $reflFieldValue[$index];
|
||||
}
|
||||
} else if ( ! $reflFieldValue) {
|
||||
$reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
|
||||
$this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
|
||||
} else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
|
||||
$reflFieldValue->setInitialized(true);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ use Doctrine\DBAL\Schema\Column;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use function preg_replace;
|
||||
|
||||
/**
|
||||
* The DatabaseDriver reverse engineers the mapping metadata from a database.
|
||||
@@ -548,7 +549,7 @@ class DatabaseDriver implements MappingDriver
|
||||
|
||||
// Replace _id if it is a foreignkey column
|
||||
if ($fk) {
|
||||
$columnName = str_replace('_id', '', $columnName);
|
||||
$columnName = preg_replace('/_id$/', '', $columnName);
|
||||
}
|
||||
|
||||
return Inflector::camelize($columnName);
|
||||
|
||||
@@ -20,17 +20,29 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use const CASE_LOWER;
|
||||
use const CASE_UPPER;
|
||||
use function preg_replace;
|
||||
use function strpos;
|
||||
use function strrpos;
|
||||
use function strtolower;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* Naming strategy implementing the underscore naming convention.
|
||||
* Converts 'MyEntity' to 'my_entity' or 'MY_ENTITY'.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.3
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class UnderscoreNamingStrategy implements NamingStrategy
|
||||
{
|
||||
private const DEFAULT_PATTERN = '/(?<=[a-z])([A-Z])/';
|
||||
private const PATTERN_FOR_PROPERTIES = '/(?<=[a-z0-9])([A-Z])/';
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
@@ -57,7 +69,7 @@ class UnderscoreNamingStrategy implements NamingStrategy
|
||||
/**
|
||||
* Sets string case CASE_LOWER | CASE_UPPER.
|
||||
* Alphabetic characters converted to lowercase or uppercase.
|
||||
*
|
||||
*
|
||||
* @param integer $case
|
||||
*
|
||||
* @return void
|
||||
@@ -84,7 +96,7 @@ class UnderscoreNamingStrategy implements NamingStrategy
|
||||
*/
|
||||
public function propertyToColumnName($propertyName, $className = null)
|
||||
{
|
||||
return $this->underscore($propertyName);
|
||||
return $this->underscore($propertyName, self::PATTERN_FOR_PROPERTIES);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +120,7 @@ class UnderscoreNamingStrategy implements NamingStrategy
|
||||
*/
|
||||
public function joinColumnName($propertyName, $className = null)
|
||||
{
|
||||
return $this->underscore($propertyName) . '_' . $this->referenceColumnName();
|
||||
return $this->underscore($propertyName, self::PATTERN_FOR_PROPERTIES) . '_' . $this->referenceColumnName();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,7 +130,7 @@ class UnderscoreNamingStrategy implements NamingStrategy
|
||||
{
|
||||
return $this->classToTableName($sourceEntity) . '_' . $this->classToTableName($targetEntity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -127,15 +139,10 @@ class UnderscoreNamingStrategy implements NamingStrategy
|
||||
return $this->classToTableName($entityName) . '_' .
|
||||
($referencedColumnName ?: $this->referenceColumnName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function underscore($string)
|
||||
|
||||
private function underscore(string $string, string $pattern = self::DEFAULT_PATTERN) : string
|
||||
{
|
||||
$string = preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $string);
|
||||
$string = preg_replace($pattern, '_$1', $string);
|
||||
|
||||
if ($this->case === CASE_UPPER) {
|
||||
return strtoupper($string);
|
||||
|
||||
@@ -25,7 +25,6 @@ use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Selectable;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use function array_merge;
|
||||
use function get_class;
|
||||
|
||||
/**
|
||||
@@ -567,9 +566,7 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
|
||||
if ($this->association['isOwningSide'] && $this->owner) {
|
||||
$this->changed();
|
||||
|
||||
if (! $this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingDeferredExplicit()) {
|
||||
$uow->scheduleCollectionDeletion($this);
|
||||
}
|
||||
$uow->scheduleCollectionDeletion($this);
|
||||
|
||||
$this->takeSnapshot();
|
||||
}
|
||||
@@ -672,7 +669,7 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
|
||||
|
||||
$criteria = clone $criteria;
|
||||
$criteria->where($expression);
|
||||
$criteria->orderBy(array_merge($this->association['orderBy'] ?? [], $criteria->getOrderings()));
|
||||
$criteria->orderBy($criteria->getOrderings() ?: $this->association['orderBy'] ?? []);
|
||||
|
||||
$persister = $this->em->getUnitOfWork()->getEntityPersister($this->association['targetEntity']);
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ final class Query extends AbstractQuery
|
||||
/**
|
||||
* Cached DQL query.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
private $_dql = null;
|
||||
|
||||
@@ -159,7 +159,7 @@ final class Query extends AbstractQuery
|
||||
/**
|
||||
* The first result to return (the "offset").
|
||||
*
|
||||
* @var integer
|
||||
* @var int|null
|
||||
*/
|
||||
private $_firstResult = null;
|
||||
|
||||
@@ -587,7 +587,7 @@ final class Query extends AbstractQuery
|
||||
/**
|
||||
* Returns the DQL query that is represented by this query object.
|
||||
*
|
||||
* @return string DQL query.
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDQL()
|
||||
{
|
||||
@@ -640,7 +640,7 @@ final class Query extends AbstractQuery
|
||||
* Gets the position of the first result the query object was set to retrieve (the "offset").
|
||||
* Returns NULL if {@link setFirstResult} was not applied to this query.
|
||||
*
|
||||
* @return integer The position of the first result.
|
||||
* @return int|null The position of the first result.
|
||||
*/
|
||||
public function getFirstResult()
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Inflector\Inflector;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use function str_replace;
|
||||
|
||||
/**
|
||||
* Generic class used to generate PHP5 entity classes from ClassMetadataInfo instances.
|
||||
@@ -1679,7 +1680,7 @@ public function __construct(<params>)
|
||||
}
|
||||
|
||||
if (isset($fieldMapping['options']['comment']) && $fieldMapping['options']['comment']) {
|
||||
$options[] = '"comment"="' . $fieldMapping['options']['comment'] .'"';
|
||||
$options[] = '"comment"="' . str_replace('"', '""', $fieldMapping['options']['comment']) . '"';
|
||||
}
|
||||
|
||||
if (isset($fieldMapping['options']['collation']) && $fieldMapping['options']['collation']) {
|
||||
|
||||
@@ -39,10 +39,9 @@ use Doctrine\ORM\Query\AST\SelectStatement;
|
||||
*/
|
||||
class LimitSubqueryWalker extends TreeWalkerAdapter
|
||||
{
|
||||
/**
|
||||
* ID type hint.
|
||||
*/
|
||||
const IDENTIFIER_TYPE = 'doctrine_paginator.id.type';
|
||||
public const IDENTIFIER_TYPE = 'doctrine_paginator.id.type';
|
||||
|
||||
public const FORCE_DBAL_TYPE_CONVERSION = 'doctrine_paginator.scalar_result.force_dbal_type_conversion';
|
||||
|
||||
/**
|
||||
* Counter for generating unique order column aliases.
|
||||
@@ -82,6 +81,8 @@ class LimitSubqueryWalker extends TreeWalkerAdapter
|
||||
Type::getType($rootClass->fieldMappings[$identifier]['type'])
|
||||
);
|
||||
|
||||
$this->_getQuery()->setHint(self::FORCE_DBAL_TYPE_CONVERSION, true);
|
||||
|
||||
$pathExpression = new PathExpression(
|
||||
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION,
|
||||
$rootAlias,
|
||||
|
||||
@@ -166,6 +166,7 @@ class Paginator implements \Countable, \IteratorAggregate
|
||||
$whereInQuery->setFirstResult(null)->setMaxResults(null);
|
||||
$whereInQuery->setParameter(WhereInWalker::PAGINATOR_ID_ALIAS, $ids);
|
||||
$whereInQuery->setCacheable($this->query->isCacheable());
|
||||
$whereInQuery->expireQueryCache();
|
||||
|
||||
$result = $whereInQuery->getResult($this->query->getHydrationMode());
|
||||
} else {
|
||||
|
||||
@@ -709,6 +709,11 @@ class SchemaTool
|
||||
}
|
||||
|
||||
$compositeName = $theJoinTable->getName().'.'.implode('', $localColumns);
|
||||
|
||||
if (! $this->platform->supportsForeignKeyConstraints()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($addedFks[$compositeName])
|
||||
&& ($foreignTableName != $addedFks[$compositeName]['foreignTableName']
|
||||
|| 0 < count(array_diff($foreignColumns, $addedFks[$compositeName]['foreignColumns'])))
|
||||
|
||||
@@ -46,6 +46,7 @@ use Doctrine\ORM\Utility\IdentifierFlattener;
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
use UnexpectedValueException;
|
||||
use function get_class;
|
||||
|
||||
/**
|
||||
* The UnitOfWork is responsible for tracking changes to objects during an
|
||||
@@ -380,7 +381,18 @@ class UnitOfWork implements PropertyChangedListener
|
||||
try {
|
||||
// Collection deletions (deletions of complete collections)
|
||||
foreach ($this->collectionDeletions as $collectionToDelete) {
|
||||
$this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
|
||||
if (! $collectionToDelete instanceof PersistentCollection) {
|
||||
$this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Deferred explicit tracked collections can be removed only when owning relation was persisted
|
||||
$owner = $collectionToDelete->getOwner();
|
||||
|
||||
if ($this->em->getClassMetadata(get_class($owner))->isChangeTrackingDeferredImplicit() || $this->isScheduledForDirtyCheck($owner)) {
|
||||
$this->getCollectionPersister($collectionToDelete->getMapping())->delete($collectionToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->entityInsertions) {
|
||||
@@ -2483,22 +2495,23 @@ class UnitOfWork implements PropertyChangedListener
|
||||
public function clear($entityName = null)
|
||||
{
|
||||
if ($entityName === null) {
|
||||
$this->identityMap =
|
||||
$this->entityIdentifiers =
|
||||
$this->originalEntityData =
|
||||
$this->entityChangeSets =
|
||||
$this->entityStates =
|
||||
$this->scheduledForSynchronization =
|
||||
$this->entityInsertions =
|
||||
$this->entityUpdates =
|
||||
$this->entityDeletions =
|
||||
$this->identityMap =
|
||||
$this->entityIdentifiers =
|
||||
$this->originalEntityData =
|
||||
$this->entityChangeSets =
|
||||
$this->entityStates =
|
||||
$this->scheduledForSynchronization =
|
||||
$this->entityInsertions =
|
||||
$this->entityUpdates =
|
||||
$this->entityDeletions =
|
||||
$this->nonCascadedNewDetectedEntities =
|
||||
$this->collectionDeletions =
|
||||
$this->collectionUpdates =
|
||||
$this->extraUpdates =
|
||||
$this->readOnlyObjects =
|
||||
$this->visitedCollections =
|
||||
$this->orphanRemovals = [];
|
||||
$this->collectionDeletions =
|
||||
$this->collectionUpdates =
|
||||
$this->extraUpdates =
|
||||
$this->readOnlyObjects =
|
||||
$this->visitedCollections =
|
||||
$this->eagerLoadingEntities =
|
||||
$this->orphanRemovals = [];
|
||||
} else {
|
||||
$this->clearIdentityMapForEntityName($entityName);
|
||||
$this->clearEntityInsertionsForEntityName($entityName);
|
||||
|
||||
@@ -35,7 +35,7 @@ class Version
|
||||
/**
|
||||
* Current Doctrine Version
|
||||
*/
|
||||
const VERSION = '2.6.4-DEV';
|
||||
const VERSION = '2.6.5';
|
||||
|
||||
/**
|
||||
* Compares a Doctrine version with the current one.
|
||||
|
||||
@@ -2,19 +2,24 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\DBAL\Types\Type as DBALType;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
use Doctrine\Tests\DbalTypes\CustomIdObject;
|
||||
use Doctrine\Tests\DbalTypes\CustomIdObjectType;
|
||||
use Doctrine\Tests\Models\CMS\CmsArticle;
|
||||
use Doctrine\Tests\Models\CMS\CmsEmail;
|
||||
use Doctrine\Tests\Models\CMS\CmsGroup;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\Models\Company\CompanyManager;
|
||||
use Doctrine\Tests\Models\CustomType\CustomIdObjectTypeParent;
|
||||
use Doctrine\Tests\Models\Pagination\Company;
|
||||
use Doctrine\Tests\Models\Pagination\Department;
|
||||
use Doctrine\Tests\Models\Pagination\Logo;
|
||||
use Doctrine\Tests\Models\Pagination\User1;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use ReflectionMethod;
|
||||
use function iterator_to_array;
|
||||
|
||||
/**
|
||||
* @group DDC-1613
|
||||
@@ -26,6 +31,14 @@ class PaginationTest extends OrmFunctionalTestCase
|
||||
$this->useModelSet('cms');
|
||||
$this->useModelSet('pagination');
|
||||
$this->useModelSet('company');
|
||||
$this->useModelSet('custom_id_object_type');
|
||||
|
||||
if (DBALType::hasType(CustomIdObjectType::NAME)) {
|
||||
DBALType::overrideType(CustomIdObjectType::NAME, CustomIdObjectType::class);
|
||||
} else {
|
||||
DBALType::addType(CustomIdObjectType::NAME, CustomIdObjectType::class);
|
||||
}
|
||||
|
||||
parent::setUp();
|
||||
$this->populate();
|
||||
}
|
||||
@@ -641,6 +654,27 @@ class PaginationTest extends OrmFunctionalTestCase
|
||||
$this->assertEquals(1, $paginator->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group GH-7890
|
||||
*/
|
||||
public function testCustomIdTypeWithoutOutputWalker()
|
||||
{
|
||||
$this->_em->persist(new CustomIdObjectTypeParent(new CustomIdObject('foo')));
|
||||
$this->_em->flush();
|
||||
|
||||
$dql = 'SELECT p FROM Doctrine\Tests\Models\CustomType\CustomIdObjectTypeParent p';
|
||||
$query = $this->_em->createQuery($dql);
|
||||
|
||||
$paginator = new Paginator($query, true);
|
||||
$paginator->setUseOutputWalkers(false);
|
||||
|
||||
$matchedItems = iterator_to_array($paginator->getIterator());
|
||||
|
||||
self::assertCount(1, $matchedItems);
|
||||
self::assertInstanceOf(CustomIdObjectTypeParent::class, $matchedItems[0]);
|
||||
self::assertSame('foo', (string) $matchedItems[0]->id);
|
||||
}
|
||||
|
||||
public function testCountQueryStripsParametersInSelect()
|
||||
{
|
||||
$query = $this->_em->createQuery(
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace Doctrine\Tests\ORM\Functional\SchemaTool;
|
||||
use Doctrine\ORM\Tools\SchemaTool;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use Doctrine\Tests\Models;
|
||||
use function method_exists;
|
||||
use function sprintf;
|
||||
|
||||
class MySqlSchemaToolTest extends OrmFunctionalTestCase
|
||||
{
|
||||
@@ -28,15 +30,16 @@ class MySqlSchemaToolTest extends OrmFunctionalTestCase
|
||||
|
||||
$tool = new SchemaTool($this->_em);
|
||||
$sql = $tool->getCreateSchemaSql($classes);
|
||||
$collation = $this->getColumnCollationDeclarationSQL('utf8_unicode_ci');
|
||||
|
||||
$this->assertEquals("CREATE TABLE cms_groups (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[0]);
|
||||
$this->assertEquals("CREATE TABLE cms_users (id INT AUTO_INCREMENT NOT NULL, email_id INT DEFAULT NULL, status VARCHAR(50) DEFAULT NULL, username VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_3AF03EC5F85E0677 (username), UNIQUE INDEX UNIQ_3AF03EC5A832C1C9 (email_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[1]);
|
||||
$this->assertEquals("CREATE TABLE cms_users_groups (user_id INT NOT NULL, group_id INT NOT NULL, INDEX IDX_7EA9409AA76ED395 (user_id), INDEX IDX_7EA9409AFE54D947 (group_id), PRIMARY KEY(user_id, group_id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[2]);
|
||||
$this->assertEquals("CREATE TABLE cms_users_tags (user_id INT NOT NULL, tag_id INT NOT NULL, INDEX IDX_93F5A1ADA76ED395 (user_id), INDEX IDX_93F5A1ADBAD26311 (tag_id), PRIMARY KEY(user_id, tag_id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[3]);
|
||||
$this->assertEquals("CREATE TABLE cms_tags (id INT AUTO_INCREMENT NOT NULL, tag_name VARCHAR(50) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[4]);
|
||||
$this->assertEquals("CREATE TABLE cms_addresses (id INT AUTO_INCREMENT NOT NULL, user_id INT DEFAULT NULL, country VARCHAR(50) NOT NULL, zip VARCHAR(50) NOT NULL, city VARCHAR(50) NOT NULL, UNIQUE INDEX UNIQ_ACAC157BA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[5]);
|
||||
$this->assertEquals("CREATE TABLE cms_emails (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(250) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[6]);
|
||||
$this->assertEquals("CREATE TABLE cms_phonenumbers (phonenumber VARCHAR(50) NOT NULL, user_id INT DEFAULT NULL, INDEX IDX_F21F790FA76ED395 (user_id), PRIMARY KEY(phonenumber)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[7]);
|
||||
$this->assertEquals('CREATE TABLE cms_groups (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[0]);
|
||||
$this->assertEquals('CREATE TABLE cms_users (id INT AUTO_INCREMENT NOT NULL, email_id INT DEFAULT NULL, status VARCHAR(50) DEFAULT NULL, username VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_3AF03EC5F85E0677 (username), UNIQUE INDEX UNIQ_3AF03EC5A832C1C9 (email_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[1]);
|
||||
$this->assertEquals('CREATE TABLE cms_users_groups (user_id INT NOT NULL, group_id INT NOT NULL, INDEX IDX_7EA9409AA76ED395 (user_id), INDEX IDX_7EA9409AFE54D947 (group_id), PRIMARY KEY(user_id, group_id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[2]);
|
||||
$this->assertEquals('CREATE TABLE cms_users_tags (user_id INT NOT NULL, tag_id INT NOT NULL, INDEX IDX_93F5A1ADA76ED395 (user_id), INDEX IDX_93F5A1ADBAD26311 (tag_id), PRIMARY KEY(user_id, tag_id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[3]);
|
||||
$this->assertEquals('CREATE TABLE cms_tags (id INT AUTO_INCREMENT NOT NULL, tag_name VARCHAR(50) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[4]);
|
||||
$this->assertEquals('CREATE TABLE cms_addresses (id INT AUTO_INCREMENT NOT NULL, user_id INT DEFAULT NULL, country VARCHAR(50) NOT NULL, zip VARCHAR(50) NOT NULL, city VARCHAR(50) NOT NULL, UNIQUE INDEX UNIQ_ACAC157BA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[5]);
|
||||
$this->assertEquals('CREATE TABLE cms_emails (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(250) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[6]);
|
||||
$this->assertEquals('CREATE TABLE cms_phonenumbers (phonenumber VARCHAR(50) NOT NULL, user_id INT DEFAULT NULL, INDEX IDX_F21F790FA76ED395 (user_id), PRIMARY KEY(phonenumber)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[7]);
|
||||
$this->assertEquals("ALTER TABLE cms_users ADD CONSTRAINT FK_3AF03EC5A832C1C9 FOREIGN KEY (email_id) REFERENCES cms_emails (id)", $sql[8]);
|
||||
$this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AA76ED395 FOREIGN KEY (user_id) REFERENCES cms_users (id)", $sql[9]);
|
||||
$this->assertEquals("ALTER TABLE cms_users_groups ADD CONSTRAINT FK_7EA9409AFE54D947 FOREIGN KEY (group_id) REFERENCES cms_groups (id)", $sql[10]);
|
||||
@@ -48,6 +51,15 @@ class MySqlSchemaToolTest extends OrmFunctionalTestCase
|
||||
$this->assertEquals(15, count($sql));
|
||||
}
|
||||
|
||||
private function getColumnCollationDeclarationSQL(string $collation) : string
|
||||
{
|
||||
if (method_exists($this->_em->getConnection()->getDatabasePlatform(), 'getColumnCollationDeclarationSQL')) {
|
||||
return $this->_em->getConnection()->getDatabasePlatform()->getColumnCollationDeclarationSQL($collation);
|
||||
}
|
||||
|
||||
return sprintf('COLLATE %s', $collation);
|
||||
}
|
||||
|
||||
public function testGetCreateSchemaSql2()
|
||||
{
|
||||
$classes = [
|
||||
@@ -56,9 +68,10 @@ class MySqlSchemaToolTest extends OrmFunctionalTestCase
|
||||
|
||||
$tool = new SchemaTool($this->_em);
|
||||
$sql = $tool->getCreateSchemaSql($classes);
|
||||
$collation = $this->getColumnCollationDeclarationSQL('utf8_unicode_ci');
|
||||
|
||||
$this->assertEquals(1, count($sql));
|
||||
$this->assertEquals("CREATE TABLE decimal_model (id INT AUTO_INCREMENT NOT NULL, `decimal` NUMERIC(5, 2) NOT NULL, `high_scale` NUMERIC(14, 4) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[0]);
|
||||
$this->assertEquals('CREATE TABLE decimal_model (id INT AUTO_INCREMENT NOT NULL, `decimal` NUMERIC(5, 2) NOT NULL, `high_scale` NUMERIC(14, 4) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[0]);
|
||||
}
|
||||
|
||||
public function testGetCreateSchemaSql3()
|
||||
@@ -69,9 +82,10 @@ class MySqlSchemaToolTest extends OrmFunctionalTestCase
|
||||
|
||||
$tool = new SchemaTool($this->_em);
|
||||
$sql = $tool->getCreateSchemaSql($classes);
|
||||
$collation = $this->getColumnCollationDeclarationSQL('utf8_unicode_ci');
|
||||
|
||||
$this->assertEquals(1, count($sql));
|
||||
$this->assertEquals("CREATE TABLE boolean_model (id INT AUTO_INCREMENT NOT NULL, booleanField TINYINT(1) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[0]);
|
||||
$this->assertEquals('CREATE TABLE boolean_model (id INT AUTO_INCREMENT NOT NULL, booleanField TINYINT(1) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,9 @@ class DDC2138Test extends OrmFunctionalTestCase
|
||||
public function testForeignKeyOnSTIWithMultipleMapping()
|
||||
{
|
||||
$em = $this->_em;
|
||||
if (! $em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$this->markTestSkipped('Platform does not support foreign keys.');
|
||||
}
|
||||
$schemaTool = new SchemaTool($em);
|
||||
|
||||
$classes = [
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use function method_exists;
|
||||
use function sprintf;
|
||||
|
||||
class DDC2182Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
public function testPassColumnOptionsToJoinColumns()
|
||||
@@ -16,11 +19,21 @@ class DDC2182Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->getClassMetadata(DDC2182OptionChild::class),
|
||||
]
|
||||
);
|
||||
$collation = $this->getColumnCollationDeclarationSQL('utf8_unicode_ci');
|
||||
|
||||
$this->assertEquals("CREATE TABLE DDC2182OptionParent (id INT UNSIGNED NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[0]);
|
||||
$this->assertEquals("CREATE TABLE DDC2182OptionChild (id VARCHAR(255) NOT NULL, parent_id INT UNSIGNED DEFAULT NULL, INDEX IDX_B314D4AD727ACA70 (parent_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB", $sql[1]);
|
||||
$this->assertEquals('CREATE TABLE DDC2182OptionParent (id INT UNSIGNED NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[0]);
|
||||
$this->assertEquals('CREATE TABLE DDC2182OptionChild (id VARCHAR(255) NOT NULL, parent_id INT UNSIGNED DEFAULT NULL, INDEX IDX_B314D4AD727ACA70 (parent_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 ' . $collation . ' ENGINE = InnoDB', $sql[1]);
|
||||
$this->assertEquals("ALTER TABLE DDC2182OptionChild ADD CONSTRAINT FK_B314D4AD727ACA70 FOREIGN KEY (parent_id) REFERENCES DDC2182OptionParent (id)", $sql[2]);
|
||||
}
|
||||
|
||||
private function getColumnCollationDeclarationSQL(string $collation) : string
|
||||
{
|
||||
if (method_exists($this->_em->getConnection()->getDatabasePlatform(), 'getColumnCollationDeclarationSQL')) {
|
||||
return $this->_em->getConnection()->getDatabasePlatform()->getColumnCollationDeclarationSQL($collation);
|
||||
}
|
||||
|
||||
return sprintf('COLLATE %s', $collation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\DBAL\Schema\Table;
|
||||
use Doctrine\Tests\ORM\Functional\DatabaseDriverTestCase;
|
||||
|
||||
/**
|
||||
* Verifies that associations/columns with an inline '_id' get named properly
|
||||
*
|
||||
* Github issue: 7684
|
||||
*/
|
||||
class GH7684 extends DatabaseDriverTestCase
|
||||
{
|
||||
public function testIssue() : void
|
||||
{
|
||||
if (! $this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$this->markTestSkipped('Platform does not support foreign keys.');
|
||||
}
|
||||
|
||||
$table1 = new Table('GH7684_identity_test_table');
|
||||
$table1->addColumn('id', 'integer');
|
||||
$table1->setPrimaryKey(['id']);
|
||||
|
||||
$table2 = new Table('GH7684_identity_test_assoc_table');
|
||||
$table2->addColumn('id', 'integer');
|
||||
$table2->addColumn('gh7684_identity_test_id', 'integer');
|
||||
$table2->setPrimaryKey(['id']);
|
||||
$table2->addForeignKeyConstraint('GH7684_identity_test', ['gh7684_identity_test_id'], ['id']);
|
||||
|
||||
$metadatas = $this->convertToClassMetadata([$table1, $table2]);
|
||||
$metadata = $metadatas['Gh7684IdentityTestAssocTable'];
|
||||
|
||||
$this->assertArrayHasKey('gh7684IdentityTest', $metadata->associationMappings);
|
||||
}
|
||||
}
|
||||
@@ -43,8 +43,23 @@ final class GH7761Test extends OrmFunctionalTestCase
|
||||
|
||||
$entity = $this->_em->find(GH7761Entity::class, 1);
|
||||
self::assertCount(1, $entity->children);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group GH-7862
|
||||
*/
|
||||
public function testCollectionClearDoesClearIfPersisted() : void
|
||||
{
|
||||
/** @var GH7761Entity $entity */
|
||||
$entity = $this->_em->find(GH7761Entity::class, 1);
|
||||
$entity->children->clear();
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$entity = $this->_em->find(GH7761Entity::class, 1);
|
||||
self::assertCount(0, $entity->children);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Cache\ClearableCache;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\StringType;
|
||||
@@ -11,6 +12,7 @@ use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use function array_map;
|
||||
use function assert;
|
||||
use function is_string;
|
||||
use function iterator_to_array;
|
||||
|
||||
@@ -53,6 +55,9 @@ class GH7820Test extends OrmFunctionalTestCase
|
||||
|
||||
$this->setUpEntitySchema([GH7820Line::class]);
|
||||
|
||||
$this->_em->createQuery('DELETE FROM ' . GH7820Line::class . ' l')
|
||||
->execute();
|
||||
|
||||
foreach (self::SONG as $index => $line) {
|
||||
$this->_em->persist(new GH7820Line(GH7820LineText::fromText($line), $index));
|
||||
}
|
||||
@@ -73,6 +78,41 @@ class GH7820Test extends OrmFunctionalTestCase
|
||||
}, iterator_to_array(new Paginator($query)))
|
||||
);
|
||||
}
|
||||
|
||||
/** @group GH7837 */
|
||||
public function testWillFindSongsInPaginatorEvenWithCachedQueryParsing() : void
|
||||
{
|
||||
$cache = $this->_em->getConfiguration()
|
||||
->getQueryCacheImpl();
|
||||
|
||||
assert($cache instanceof ClearableCache);
|
||||
|
||||
$cache->deleteAll();
|
||||
|
||||
$query = $this->_em->getRepository(GH7820Line::class)
|
||||
->createQueryBuilder('l')
|
||||
->orderBy('l.lineNumber', Criteria::ASC);
|
||||
|
||||
self::assertSame(
|
||||
self::SONG,
|
||||
array_map(static function (GH7820Line $line) : string {
|
||||
return $line->toString();
|
||||
}, iterator_to_array(new Paginator($query))),
|
||||
'Expected to return expected data before query cache is populated with DQL -> SQL translation. Were SQL parameters translated?'
|
||||
);
|
||||
|
||||
$query = $this->_em->getRepository(GH7820Line::class)
|
||||
->createQueryBuilder('l')
|
||||
->orderBy('l.lineNumber', Criteria::ASC);
|
||||
|
||||
self::assertSame(
|
||||
self::SONG,
|
||||
array_map(static function (GH7820Line $line) : string {
|
||||
return $line->toString();
|
||||
}, iterator_to_array(new Paginator($query))),
|
||||
'Expected to return expected data even when DQL -> SQL translation is present in cache. Were SQL parameters translated again?'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use function assert;
|
||||
|
||||
/**
|
||||
* @group GH7836
|
||||
*/
|
||||
class GH7836Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema([GH7836ParentEntity::class, GH7836ChildEntity::class]);
|
||||
|
||||
$parent = new GH7836ParentEntity();
|
||||
$parent->addChild(100, 'foo');
|
||||
$parent->addChild(100, 'bar');
|
||||
$parent->addChild(200, 'baz');
|
||||
|
||||
$this->_em->persist($parent);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
}
|
||||
|
||||
public function testMatchingRespectsCollectionOrdering() : void
|
||||
{
|
||||
$parent = $this->_em->find(GH7836ParentEntity::class, 1);
|
||||
assert($parent instanceof GH7836ParentEntity);
|
||||
|
||||
$children = $parent->getChildren()->matching(Criteria::create());
|
||||
|
||||
self::assertSame(100, $children[0]->position);
|
||||
self::assertSame('bar', $children[0]->name);
|
||||
self::assertSame(100, $children[1]->position);
|
||||
self::assertSame('foo', $children[1]->name);
|
||||
self::assertSame(200, $children[2]->position);
|
||||
self::assertSame('baz', $children[2]->name);
|
||||
}
|
||||
|
||||
public function testMatchingOverrulesCollectionOrdering() : void
|
||||
{
|
||||
$parent = $this->_em->find(GH7836ParentEntity::class, 1);
|
||||
assert($parent instanceof GH7836ParentEntity);
|
||||
|
||||
$children = $parent->getChildren()->matching(Criteria::create()->orderBy(['position' => 'DESC', 'name' => 'ASC']));
|
||||
|
||||
self::assertSame(200, $children[0]->position);
|
||||
self::assertSame('baz', $children[0]->name);
|
||||
self::assertSame(100, $children[1]->position);
|
||||
self::assertSame('bar', $children[1]->name);
|
||||
self::assertSame(100, $children[2]->position);
|
||||
self::assertSame('foo', $children[2]->name);
|
||||
}
|
||||
|
||||
public function testMatchingKeepsOrderOfCriteriaOrderingKeys() : void
|
||||
{
|
||||
$parent = $this->_em->find(GH7836ParentEntity::class, 1);
|
||||
assert($parent instanceof GH7836ParentEntity);
|
||||
|
||||
$children = $parent->getChildren()->matching(Criteria::create()->orderBy(['name' => 'ASC', 'position' => 'ASC']));
|
||||
|
||||
self::assertSame(100, $children[0]->position);
|
||||
self::assertSame('bar', $children[0]->name);
|
||||
self::assertSame(200, $children[1]->position);
|
||||
self::assertSame('baz', $children[1]->name);
|
||||
self::assertSame(100, $children[2]->position);
|
||||
self::assertSame('foo', $children[2]->name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7836ParentEntity
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity=GH7836ChildEntity::class, mappedBy="parent", fetch="EXTRA_LAZY", cascade={"persist"})
|
||||
* @OrderBy({"position" = "ASC", "name" = "ASC"})
|
||||
*/
|
||||
private $children;
|
||||
|
||||
public function addChild(int $position, string $name) : void
|
||||
{
|
||||
$this->children[] = new GH7836ChildEntity($this, $position, $name);
|
||||
}
|
||||
|
||||
public function getChildren() : PersistentCollection
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7836ChildEntity
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/** @Column(type="integer") */
|
||||
public $position;
|
||||
|
||||
/** @Column(type="string") */
|
||||
public $name;
|
||||
|
||||
/** @ManyToOne(targetEntity=GH7836ParentEntity::class, inversedBy="children") */
|
||||
private $parent;
|
||||
|
||||
public function __construct(GH7836ParentEntity $parent, int $position, string $name)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->position = $position;
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @group GH7841
|
||||
*/
|
||||
class GH7841Test extends OrmFunctionalTestCase
|
||||
{
|
||||
public function testForeignKeysNotCompare() : void
|
||||
{
|
||||
if ($this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) {
|
||||
$this->markTestSkipped('Test for platforms without foreign keys support');
|
||||
}
|
||||
$class = $this->_em->getClassMetadata(GH7841Child::class);
|
||||
$this->_schemaTool->updateSchema([$class], true);
|
||||
$diff = $this->_schemaTool->getUpdateSchemaSql([$class], true);
|
||||
|
||||
self::assertEmpty($diff);
|
||||
|
||||
$this->_schemaTool->dropSchema([$class]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7841Parent
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @OneToMany(targetEntity=GH7841Child::class, mappedBy="parent") */
|
||||
public $children;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->children = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7841Child
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @ManyToOne(targetEntity=GH7841Parent::class) */
|
||||
public $parent;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\ORM\Decorator\EntityManagerDecorator;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\Tests\Mocks\ConnectionMock;
|
||||
use Doctrine\Tests\Mocks\DriverMock;
|
||||
use Doctrine\Tests\Mocks\EntityManagerMock;
|
||||
use Doctrine\Tests\OrmTestCase;
|
||||
|
||||
/**
|
||||
* @group GH7869
|
||||
*/
|
||||
class GH7869Test extends OrmTestCase
|
||||
{
|
||||
public function testDQLDeferredEagerLoad()
|
||||
{
|
||||
$decoratedEm = EntityManagerMock::create(new ConnectionMock([], new DriverMock()));
|
||||
|
||||
$em = $this->getMockBuilder(EntityManagerDecorator::class)
|
||||
->setConstructorArgs([$decoratedEm])
|
||||
->setMethods(['getClassMetadata'])
|
||||
->getMock();
|
||||
|
||||
$em->expects($this->exactly(2))
|
||||
->method('getClassMetadata')
|
||||
->willReturnCallback([$decoratedEm, 'getClassMetadata']);
|
||||
|
||||
$hints = [
|
||||
UnitOfWork::HINT_DEFEREAGERLOAD => true,
|
||||
'fetchMode' => [GH7869Appointment::class => ['patient' => ClassMetadata::FETCH_EAGER]],
|
||||
];
|
||||
|
||||
$uow = new UnitOfWork($em);
|
||||
$uow->createEntity(GH7869Appointment::class, ['id' => 1, 'patient_id' => 1], $hints);
|
||||
$uow->clear();
|
||||
$uow->triggerEagerLoads();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7869Appointment
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @OneToOne(targetEntity="GH7869Patient", inversedBy="appointment", fetch="EAGER") */
|
||||
public $patient;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class GH7869Patient
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @OneToOne(targetEntity="GH7869Appointment", mappedBy="patient") */
|
||||
public $appointment;
|
||||
}
|
||||
@@ -1,38 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Mapping;
|
||||
|
||||
use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
|
||||
use Doctrine\ORM\Mapping\DefaultNamingStrategy;
|
||||
use Doctrine\ORM\Mapping\NamingStrategy;
|
||||
use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
|
||||
use Doctrine\Tests\ORM\Mapping\NamingStrategy\JoinColumnClassNamingStrategy;
|
||||
use Doctrine\Tests\OrmTestCase;
|
||||
use const CASE_LOWER;
|
||||
use const CASE_UPPER;
|
||||
|
||||
/**
|
||||
* @group DDC-559
|
||||
*/
|
||||
class NamingStrategyTest extends OrmTestCase
|
||||
{
|
||||
/**
|
||||
* @return DefaultNamingStrategy
|
||||
*/
|
||||
static private function defaultNaming()
|
||||
private static function defaultNaming() : DefaultNamingStrategy
|
||||
{
|
||||
return new DefaultNamingStrategy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UnderscoreNamingStrategy
|
||||
*/
|
||||
static private function underscoreNamingLower()
|
||||
private static function underscoreNamingLower() : UnderscoreNamingStrategy
|
||||
{
|
||||
return new UnderscoreNamingStrategy(CASE_LOWER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UnderscoreNamingStrategy
|
||||
*/
|
||||
static private function underscoreNamingUpper()
|
||||
private static function underscoreNamingUpper() : UnderscoreNamingStrategy
|
||||
{
|
||||
return new UnderscoreNamingStrategy(CASE_UPPER);
|
||||
}
|
||||
@@ -40,113 +35,73 @@ class NamingStrategyTest extends OrmTestCase
|
||||
/**
|
||||
* Data Provider for NamingStrategy#classToTableName
|
||||
*
|
||||
* @return array
|
||||
* @return array<NamingStrategy|string>
|
||||
*/
|
||||
static public function dataClassToTableName()
|
||||
public static function dataClassToTableName() : array
|
||||
{
|
||||
return [
|
||||
// DefaultNamingStrategy
|
||||
[
|
||||
self::defaultNaming(), 'SomeClassName',
|
||||
'SomeClassName'
|
||||
],
|
||||
[
|
||||
self::defaultNaming(), 'SomeClassName',
|
||||
'\SomeClassName'
|
||||
],
|
||||
[
|
||||
self::defaultNaming(), 'Name',
|
||||
'\Some\Class\Name'
|
||||
],
|
||||
[self::defaultNaming(), 'SomeClassName', 'SomeClassName'],
|
||||
[self::defaultNaming(), 'SomeClassName', '\SomeClassName'],
|
||||
[self::defaultNaming(), 'Name', '\Some\Class\Name'],
|
||||
|
||||
// UnderscoreNamingStrategy
|
||||
[
|
||||
self::underscoreNamingLower(), 'some_class_name',
|
||||
'\Name\Space\SomeClassName'
|
||||
],
|
||||
[
|
||||
self::underscoreNamingLower(), 'name',
|
||||
'\Some\Class\Name'
|
||||
],
|
||||
[
|
||||
self::underscoreNamingUpper(), 'SOME_CLASS_NAME',
|
||||
'\Name\Space\SomeClassName'
|
||||
],
|
||||
[
|
||||
self::underscoreNamingUpper(), 'NAME',
|
||||
'\Some\Class\Name'
|
||||
],
|
||||
[self::underscoreNamingLower(), 'some_class_name', '\Name\Space\SomeClassName'],
|
||||
[self::underscoreNamingLower(), 'name', '\Some\Class\Name'],
|
||||
[self::underscoreNamingUpper(), 'SOME_CLASS_NAME', '\Name\Space\SomeClassName'],
|
||||
[self::underscoreNamingUpper(), 'NAME', '\Some\Class\Name'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataClassToTableName
|
||||
*/
|
||||
public function testClassToTableName(NamingStrategy $strategy, $expected, $className)
|
||||
public function testClassToTableName(NamingStrategy $strategy, string $expected, string $className) : void
|
||||
{
|
||||
$this->assertEquals($expected, $strategy->classToTableName($className));
|
||||
self::assertSame($expected, $strategy->classToTableName($className));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Provider for NamingStrategy#propertyToColumnName
|
||||
*
|
||||
* @return array
|
||||
* @return array<NamingStrategy|string>
|
||||
*/
|
||||
static public function dataPropertyToColumnName()
|
||||
public static function dataPropertyToColumnName() : array
|
||||
{
|
||||
return [
|
||||
// DefaultNamingStrategy
|
||||
[
|
||||
self::defaultNaming(), 'someProperty',
|
||||
'someProperty'
|
||||
],
|
||||
[
|
||||
self::defaultNaming(), 'SOME_PROPERTY',
|
||||
'SOME_PROPERTY'
|
||||
],
|
||||
[
|
||||
self::defaultNaming(), 'some_property',
|
||||
'some_property'
|
||||
],
|
||||
[self::defaultNaming(), 'someProperty', 'someProperty'],
|
||||
[self::defaultNaming(), 'SOME_PROPERTY', 'SOME_PROPERTY'],
|
||||
[self::defaultNaming(), 'some_property', 'some_property'],
|
||||
[self::defaultNaming(), 'base64Encoded', 'base64Encoded'],
|
||||
[self::defaultNaming(), 'base64_encoded', 'base64_encoded'],
|
||||
|
||||
// UnderscoreNamingStrategy
|
||||
[
|
||||
self::underscoreNamingLower(), 'some_property',
|
||||
'someProperty'
|
||||
],
|
||||
[
|
||||
self::underscoreNamingUpper(), 'SOME_PROPERTY',
|
||||
'someProperty'
|
||||
],
|
||||
[
|
||||
self::underscoreNamingUpper(), 'SOME_PROPERTY',
|
||||
'some_property'
|
||||
],
|
||||
[
|
||||
self::underscoreNamingUpper(), 'SOME_PROPERTY',
|
||||
'SOME_PROPERTY'
|
||||
],
|
||||
[self::underscoreNamingLower(), 'some_property', 'someProperty'],
|
||||
[self::underscoreNamingLower(), 'base64_encoded', 'base64Encoded'],
|
||||
[self::underscoreNamingLower(), 'base64encoded', 'base64encoded'],
|
||||
[self::underscoreNamingUpper(), 'SOME_PROPERTY', 'someProperty'],
|
||||
[self::underscoreNamingUpper(), 'SOME_PROPERTY', 'some_property'],
|
||||
[self::underscoreNamingUpper(), 'SOME_PROPERTY', 'SOME_PROPERTY'],
|
||||
[self::underscoreNamingUpper(), 'BASE64_ENCODED', 'base64Encoded'],
|
||||
[self::underscoreNamingUpper(), 'BASE64ENCODED', 'base64encoded'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataPropertyToColumnName
|
||||
*
|
||||
* @param NamingStrategy $strategy
|
||||
* @param string $expected
|
||||
* @param string $propertyName
|
||||
*/
|
||||
public function testPropertyToColumnName(NamingStrategy $strategy, $expected, $propertyName)
|
||||
public function testPropertyToColumnName(NamingStrategy $strategy, string $expected, string $propertyName) : void
|
||||
{
|
||||
$this->assertEquals($expected, $strategy->propertyToColumnName($propertyName));
|
||||
self::assertSame($expected, $strategy->propertyToColumnName($propertyName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Provider for NamingStrategy#referenceColumnName
|
||||
*
|
||||
* @return array
|
||||
* @return array<NamingStrategy|string>
|
||||
*/
|
||||
static public function dataReferenceColumnName()
|
||||
public static function dataReferenceColumnName() : array
|
||||
{
|
||||
return [
|
||||
// DefaultNamingStrategy
|
||||
@@ -160,30 +115,31 @@ class NamingStrategyTest extends OrmTestCase
|
||||
|
||||
/**
|
||||
* @dataProvider dataReferenceColumnName
|
||||
*
|
||||
* @param NamingStrategy $strategy
|
||||
* @param string $expected
|
||||
*/
|
||||
public function testReferenceColumnName(NamingStrategy $strategy, $expected)
|
||||
public function testReferenceColumnName(NamingStrategy $strategy, string $expected) : void
|
||||
{
|
||||
$this->assertEquals($expected, $strategy->referenceColumnName());
|
||||
self::assertSame($expected, $strategy->referenceColumnName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Provider for NamingStrategy#joinColumnName
|
||||
*
|
||||
* @return array
|
||||
* @return array<NamingStrategy|string|null>
|
||||
*/
|
||||
static public function dataJoinColumnName()
|
||||
public static function dataJoinColumnName() : array
|
||||
{
|
||||
return [
|
||||
// DefaultNamingStrategy
|
||||
[self::defaultNaming(), 'someColumn_id', 'someColumn', null],
|
||||
[self::defaultNaming(), 'some_column_id', 'some_column', null],
|
||||
[self::defaultNaming(), 'base64Encoded_id', 'base64Encoded', null],
|
||||
[self::defaultNaming(), 'base64_encoded_id', 'base64_encoded', null],
|
||||
|
||||
// UnderscoreNamingStrategy
|
||||
[self::underscoreNamingLower(), 'some_column_id', 'someColumn', null],
|
||||
[self::underscoreNamingLower(), 'base64_encoded_id', 'base64Encoded', null],
|
||||
[self::underscoreNamingUpper(), 'SOME_COLUMN_ID', 'someColumn', null],
|
||||
[self::underscoreNamingUpper(), 'BASE64_ENCODED_ID', 'base64Encoded', null],
|
||||
// JoinColumnClassNamingStrategy
|
||||
[new JoinColumnClassNamingStrategy(), 'classname_someColumn_id', 'someColumn', 'Some\ClassName'],
|
||||
[new JoinColumnClassNamingStrategy(), 'classname_some_column_id', 'some_column', 'ClassName'],
|
||||
@@ -192,131 +148,83 @@ class NamingStrategyTest extends OrmTestCase
|
||||
|
||||
/**
|
||||
* @dataProvider dataJoinColumnName
|
||||
*
|
||||
* @param NamingStrategy $strategy
|
||||
* @param string $expected
|
||||
* @param string $propertyName
|
||||
*/
|
||||
public function testJoinColumnName(NamingStrategy $strategy, $expected, $propertyName, $className = null)
|
||||
{
|
||||
$this->assertEquals($expected, $strategy->joinColumnName($propertyName, $className));
|
||||
public function testJoinColumnName(
|
||||
NamingStrategy $strategy,
|
||||
string $expected,
|
||||
string $propertyName,
|
||||
?string $className = null
|
||||
) : void {
|
||||
self::assertSame($expected, $strategy->joinColumnName($propertyName, $className));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Provider for NamingStrategy#joinTableName
|
||||
*
|
||||
* @return array
|
||||
* @return array<NamingStrategy|string|null>
|
||||
*/
|
||||
static public function dataJoinTableName()
|
||||
public static function dataJoinTableName() : array
|
||||
{
|
||||
return [
|
||||
// DefaultNamingStrategy
|
||||
[
|
||||
self::defaultNaming(), 'someclassname_classname',
|
||||
'SomeClassName', 'Some\ClassName', null,
|
||||
],
|
||||
[
|
||||
self::defaultNaming(), 'someclassname_classname',
|
||||
'\SomeClassName', 'ClassName', null,
|
||||
],
|
||||
[
|
||||
self::defaultNaming(), 'name_classname',
|
||||
'\Some\Class\Name', 'ClassName', null,
|
||||
],
|
||||
[self::defaultNaming(), 'someclassname_classname', 'SomeClassName', 'Some\ClassName', null],
|
||||
[self::defaultNaming(), 'someclassname_classname', '\SomeClassName', 'ClassName', null],
|
||||
[self::defaultNaming(), 'name_classname', '\Some\Class\Name', 'ClassName', null],
|
||||
|
||||
// UnderscoreNamingStrategy
|
||||
[
|
||||
self::underscoreNamingLower(), 'some_class_name_class_name',
|
||||
'SomeClassName', 'Some\ClassName', null,
|
||||
],
|
||||
[
|
||||
self::underscoreNamingLower(), 'some_class_name_class_name',
|
||||
'\SomeClassName', 'ClassName', null,
|
||||
],
|
||||
[
|
||||
self::underscoreNamingLower(), 'name_class_name',
|
||||
'\Some\Class\Name', 'ClassName', null,
|
||||
],
|
||||
|
||||
[
|
||||
self::underscoreNamingUpper(), 'SOME_CLASS_NAME_CLASS_NAME',
|
||||
'SomeClassName', 'Some\ClassName', null,
|
||||
],
|
||||
[
|
||||
self::underscoreNamingUpper(), 'SOME_CLASS_NAME_CLASS_NAME',
|
||||
'\SomeClassName', 'ClassName', null,
|
||||
],
|
||||
[
|
||||
self::underscoreNamingUpper(), 'NAME_CLASS_NAME',
|
||||
'\Some\Class\Name', 'ClassName', null,
|
||||
],
|
||||
[self::underscoreNamingLower(), 'some_class_name_class_name', 'SomeClassName', 'Some\ClassName', null],
|
||||
[self::underscoreNamingLower(), 'some_class_name_class_name', '\SomeClassName', 'ClassName', null],
|
||||
[self::underscoreNamingLower(), 'name_class_name', '\Some\Class\Name', 'ClassName', null],
|
||||
[self::underscoreNamingUpper(), 'SOME_CLASS_NAME_CLASS_NAME', 'SomeClassName', 'Some\ClassName', null],
|
||||
[self::underscoreNamingUpper(), 'SOME_CLASS_NAME_CLASS_NAME', '\SomeClassName', 'ClassName', null],
|
||||
[self::underscoreNamingUpper(), 'NAME_CLASS_NAME', '\Some\Class\Name', 'ClassName', null],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataJoinTableName
|
||||
*
|
||||
* @param NamingStrategy $strategy
|
||||
* @param string $expected
|
||||
* @param string $ownerEntity
|
||||
* @param string $associatedEntity
|
||||
* @param string $propertyName
|
||||
*/
|
||||
public function testJoinTableName(NamingStrategy $strategy, $expected, $ownerEntity, $associatedEntity, $propertyName = null)
|
||||
{
|
||||
$this->assertEquals($expected, $strategy->joinTableName($ownerEntity, $associatedEntity, $propertyName));
|
||||
public function testJoinTableName(
|
||||
NamingStrategy $strategy,
|
||||
string $expected,
|
||||
string $ownerEntity,
|
||||
string $associatedEntity,
|
||||
?string $propertyName = null
|
||||
) : void {
|
||||
self::assertSame($expected, $strategy->joinTableName($ownerEntity, $associatedEntity, $propertyName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Provider for NamingStrategy#joinKeyColumnName
|
||||
*
|
||||
* @return array
|
||||
* @return array<NamingStrategy|string|null>
|
||||
*/
|
||||
static public function dataJoinKeyColumnName()
|
||||
public static function dataJoinKeyColumnName() : array
|
||||
{
|
||||
return [
|
||||
// DefaultNamingStrategy
|
||||
[
|
||||
self::defaultNaming(), 'someclassname_id',
|
||||
'SomeClassName', null, null,
|
||||
],
|
||||
[
|
||||
self::defaultNaming(), 'name_identifier',
|
||||
'\Some\Class\Name', 'identifier', null,
|
||||
],
|
||||
[self::defaultNaming(), 'someclassname_id', 'SomeClassName', null, null],
|
||||
[self::defaultNaming(), 'name_identifier', '\Some\Class\Name', 'identifier', null],
|
||||
|
||||
// UnderscoreNamingStrategy
|
||||
[
|
||||
self::underscoreNamingLower(), 'some_class_name_id',
|
||||
'SomeClassName', null, null,
|
||||
],
|
||||
[
|
||||
self::underscoreNamingLower(), 'class_name_identifier',
|
||||
'\Some\Class\ClassName', 'identifier', null,
|
||||
],
|
||||
[self::underscoreNamingLower(), 'some_class_name_id', 'SomeClassName', null, null],
|
||||
[self::underscoreNamingLower(), 'class_name_identifier', '\Some\Class\ClassName', 'identifier', null],
|
||||
|
||||
[
|
||||
self::underscoreNamingUpper(), 'SOME_CLASS_NAME_ID',
|
||||
'SomeClassName', null, null,
|
||||
],
|
||||
[
|
||||
self::underscoreNamingUpper(), 'CLASS_NAME_IDENTIFIER',
|
||||
'\Some\Class\ClassName', 'IDENTIFIER', null,
|
||||
],
|
||||
[self::underscoreNamingUpper(), 'SOME_CLASS_NAME_ID', 'SomeClassName', null, null],
|
||||
[self::underscoreNamingUpper(), 'CLASS_NAME_IDENTIFIER', '\Some\Class\ClassName', 'IDENTIFIER', null],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataJoinKeyColumnName
|
||||
*
|
||||
* @param NamingStrategy $strategy
|
||||
* @param string $expected
|
||||
* @param string $propertyEntityName
|
||||
* @param string $referencedColumnName
|
||||
* @param string $propertyName
|
||||
*/
|
||||
public function testJoinKeyColumnName(NamingStrategy $strategy, $expected, $propertyEntityName, $referencedColumnName = null, $propertyName = null)
|
||||
{
|
||||
$this->assertEquals($expected, $strategy->joinKeyColumnName($propertyEntityName, $referencedColumnName, $propertyName));
|
||||
public function testJoinKeyColumnName(
|
||||
NamingStrategy $strategy,
|
||||
string $expected,
|
||||
string $propertyEntityName,
|
||||
?string $referencedColumnName = null,
|
||||
?string $propertyName = null
|
||||
) : void {
|
||||
self::assertSame($expected, $strategy->joinKeyColumnName($propertyEntityName, $referencedColumnName, $propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,16 +274,4 @@ class PersistentCollectionTest extends OrmTestCase
|
||||
|
||||
$this->collection->clear();
|
||||
}
|
||||
|
||||
public function testDoNotModifyUOWForDeferredExplicitOwnerOnClear() : void
|
||||
{
|
||||
$unitOfWork = $this->createMock(UnitOfWork::class);
|
||||
$unitOfWork->expects(self::never())->method('scheduleCollectionDeletion');
|
||||
$this->_emMock->setUnitOfWork($unitOfWork);
|
||||
|
||||
$classMetaData = $this->_emMock->getClassMetadata(ECommerceCart::class);
|
||||
$classMetaData->setChangeTrackingPolicy(ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT);
|
||||
|
||||
$this->collection->clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1223,6 +1223,10 @@ class
|
||||
'@Column(name="test", type="string", length=10, options={"comment"="testing"})',
|
||||
['type' => 'string', 'length' => 10, 'options' => ['comment' => 'testing']],
|
||||
],
|
||||
'string-comment-quote' => [
|
||||
'@Column(name="test", type="string", length=10, options={"comment"="testing ""quotes"""})',
|
||||
['type' => 'string', 'length' => 10, 'options' => ['comment' => 'testing "quotes"']],
|
||||
],
|
||||
'string-collation' => [
|
||||
'@Column(name="test", type="string", length=10, options={"collation"="utf8mb4_general_ci"})',
|
||||
['type' => 'string', 'length' => 10, 'options' => ['collation' => 'utf8mb4_general_ci']],
|
||||
|
||||
Reference in New Issue
Block a user