diff --git a/.travis.yml b/.travis.yml index 44c27230c21..7730c533b5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ language: php php: - 7.1 - 7.2 + - 7.3 - nightly env: @@ -57,6 +58,7 @@ jobs: - stage: Test if: type = cron + php: 7.3 env: DB=sqlite DEV_DEPENDENCIES install: - composer config minimum-stability dev diff --git a/UPGRADE.md b/UPGRADE.md index 851e2ddf97a..19528d89f49 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -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. diff --git a/docs/en/cookbook/aggregate-fields.rst b/docs/en/cookbook/aggregate-fields.rst index fdf830323e1..7e5a89dce2b 100644 --- a/docs/en/cookbook/aggregate-fields.rst +++ b/docs/en/cookbook/aggregate-fields.rst @@ -322,7 +322,7 @@ The aggregate field ``Account::$balance`` is now -200, however the SUM over all entries amounts yields -400. A violation of our max credit rule. -You can use both optimistic or pessimistic locking to save-guard +You can use both optimistic or pessimistic locking to safe-guard your aggregate fields against this kind of race-conditions. Reading Eric Evans DDD carefully he mentions that the "Aggregate Root" (Account in our example) needs a locking mechanism. diff --git a/docs/en/cookbook/working-with-datetime.rst b/docs/en/cookbook/working-with-datetime.rst index 98a1fb234c2..363c74fdd49 100644 --- a/docs/en/cookbook/working-with-datetime.rst +++ b/docs/en/cookbook/working-with-datetime.rst @@ -1,7 +1,7 @@ Working with DateTime Instances =============================== -There are many nitty gritty details when working with PHPs DateTime instances. You have know their inner +There are many nitty gritty details when working with PHPs DateTime instances. You have to know their inner workings pretty well not to make mistakes with date handling. This cookbook entry holds several interesting pieces of information on how to work with PHP DateTime instances in Doctrine 2. diff --git a/docs/en/reference/association-mapping.rst b/docs/en/reference/association-mapping.rst index bdb12b706f0..b7d6bb8d1df 100644 --- a/docs/en/reference/association-mapping.rst +++ b/docs/en/reference/association-mapping.rst @@ -313,8 +313,8 @@ One-To-Many, Bidirectional -------------------------- A one-to-many association has to be bidirectional, unless you are using a -join table. This is because the many side in a one-to-many association holds -the foreign key, making it the owning side. Doctrine needs the many side +join table. This is because the "many" side in a one-to-many association holds +the foreign key, making it the owning side. Doctrine needs the "many" side defined in order to understand the association. This bidirectional mapping requires the ``mappedBy`` attribute on the @@ -335,7 +335,7 @@ bidirectional many-to-one. { // ... /** - * One Product has Many Features. + * One product has many features. This is the inverse side. * @OneToMany(targetEntity="Feature", mappedBy="product") */ private $features; @@ -351,7 +351,7 @@ bidirectional many-to-one. { // ... /** - * Many Features have One Product. + * Many features have one product. This is the owning side. * @ManyToOne(targetEntity="Product", inversedBy="features") * @JoinColumn(name="product_id", referencedColumnName="id") */ diff --git a/docs/en/reference/events.rst b/docs/en/reference/events.rst index 7922d3dfd1d..b38ba581910 100644 --- a/docs/en/reference/events.rst +++ b/docs/en/reference/events.rst @@ -323,7 +323,7 @@ XML would look something like this: + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/docs/en/reference/faq.rst b/docs/en/reference/faq.rst index 45fde18d7e0..78b5b01c946 100644 --- a/docs/en/reference/faq.rst +++ b/docs/en/reference/faq.rst @@ -21,12 +21,6 @@ created database tables and columns. Entity Classes -------------- -I access a variable and its null, what is wrong? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If this variable is a public variable then you are violating one of the criteria for entities. -All properties have to be protected or private for the proxy object pattern to work. - How can I add default values to a column? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/en/reference/inheritance-mapping.rst b/docs/en/reference/inheritance-mapping.rst index d489b30b6db..d07eae1488f 100644 --- a/docs/en/reference/inheritance-mapping.rst +++ b/docs/en/reference/inheritance-mapping.rst @@ -493,7 +493,7 @@ Could be used by an entity that extends a mapped superclass to override a field * column=@Column( * name = "guest_id", * type = "integer", - length = 140 + * length = 140 * ) * ), * @AttributeOverride(name="name", @@ -501,7 +501,7 @@ Could be used by an entity that extends a mapped superclass to override a field * name = "guest_name", * nullable = false, * unique = true, - length = 240 + * length = 240 * ) * ) * }) diff --git a/docs/en/reference/limitations-and-known-issues.rst b/docs/en/reference/limitations-and-known-issues.rst index 8f273568fd1..15cde689b8d 100644 --- a/docs/en/reference/limitations-and-known-issues.rst +++ b/docs/en/reference/limitations-and-known-issues.rst @@ -63,7 +63,7 @@ Where the ``attribute_name`` column contains the key and ``$attributes``. The feature request for persistence of primitive value arrays -`is described in the DDC-298 ticket `_. +`is described in the DDC-298 ticket `_. Cascade Merge with Bi-directional Associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -71,8 +71,8 @@ Cascade Merge with Bi-directional Associations There are two bugs now that concern the use of cascade merge in combination with bi-directional associations. Make sure to study the behavior of cascade merge if you are using it: -- `DDC-875 `_ Merge can sometimes add the same entity twice into a collection -- `DDC-763 `_ Cascade merge on associated entities can insert too many rows through "Persistence by Reachability" +- `DDC-875 `_ Merge can sometimes add the same entity twice into a collection +- `DDC-763 `_ Cascade merge on associated entities can insert too many rows through "Persistence by Reachability" Custom Persisters ~~~~~~~~~~~~~~~~~ @@ -83,8 +83,8 @@ Currently there is no way to overwrite the persister implementation for a given entity, however there are several use-cases that can benefit from custom persister implementations: -- `Add Upsert Support `_ -- `Evaluate possible ways in which stored-procedures can be used `_ +- `Add Upsert Support `_ +- `Evaluate possible ways in which stored-procedures can be used `_ Persist Keys of Collections ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -94,7 +94,7 @@ PHP Arrays are ordered hash-maps and so should be the evaluate a feature that optionally persists and hydrates the keys of a Collection instance. -`Ticket DDC-213 `_ +`Ticket DDC-213 `_ Mapping many tables to one entity ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -144,9 +144,8 @@ backwards compatibility issues or where no simple fix exists (yet). We don't plan to add every bug in the tracker there, just those issues that can potentially cause nightmares or pain of any sort. -See the Open Bugs on Jira for more details on `bugs, improvement and feature -requests -`_. +See bugs, improvement and feature requests on `Github issues +`_. Identifier Quoting and Legacy Databases ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/en/reference/second-level-cache.rst b/docs/en/reference/second-level-cache.rst index 62cc5d14fdf..c4ae4f0ee7f 100644 --- a/docs/en/reference/second-level-cache.rst +++ b/docs/en/reference/second-level-cache.rst @@ -310,7 +310,7 @@ Entity cache definition .. code-block:: xml - + @@ -386,7 +386,7 @@ It caches the primary keys of association and cache each element will be cached .. code-block:: xml - + diff --git a/docs/en/reference/working-with-associations.rst b/docs/en/reference/working-with-associations.rst index de236cf4077..0b805806693 100644 --- a/docs/en/reference/working-with-associations.rst +++ b/docs/en/reference/working-with-associations.rst @@ -15,7 +15,7 @@ with associations in Doctrine: removed, not the entity itself. A collection of entities always only represents the association to the containing entities, not the entity itself. -- When a bidirectional assocation is updated, Doctrine only checks +- When a bidirectional association is updated, Doctrine only checks on one of both sides for these changes. This is called the :doc:`owning side ` of the association. - A property with a reference to many entities has to be instances of the diff --git a/docs/en/reference/working-with-objects.rst b/docs/en/reference/working-with-objects.rst index bef73cebaa3..6a33663c7c5 100644 --- a/docs/en/reference/working-with-objects.rst +++ b/docs/en/reference/working-with-objects.rst @@ -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 ----------------------------- diff --git a/docs/en/reference/xml-mapping.rst b/docs/en/reference/xml-mapping.rst index 5f013152789..f57ee461bbb 100644 --- a/docs/en/reference/xml-mapping.rst +++ b/docs/en/reference/xml-mapping.rst @@ -7,7 +7,7 @@ form of XML documents. The XML driver is backed by an XML Schema document that describes the structure of a mapping document. The most recent version of the XML Schema document is available online at -`http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd `_. +`https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd `_. In order to point to the latest version of the document of a particular stable release branch, just append the release number, i.e.: doctrine-mapping-2.0.xsd The most convenient way to work with @@ -21,7 +21,7 @@ setup for the latest code in trunk. + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> ... @@ -107,7 +107,7 @@ of several common elements: + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> @@ -768,7 +768,7 @@ entity relationship. You can define this in XML with the "association-key" attri + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/docs/en/reference/yaml-mapping.rst b/docs/en/reference/yaml-mapping.rst index ea54e277ae9..8199406ebe7 100644 --- a/docs/en/reference/yaml-mapping.rst +++ b/docs/en/reference/yaml-mapping.rst @@ -1,6 +1,10 @@ YAML Mapping ============ +.. note:: + The YAML driver is deprecated and will be removed in version 3.0. + It is strongly recommended to switch to one of the other mappings. + The YAML mapping driver enables you to provide the ORM metadata in form of YAML documents. diff --git a/docs/en/tutorials/composite-primary-keys.rst b/docs/en/tutorials/composite-primary-keys.rst index 41f0cd88e78..ef164c9db1f 100644 --- a/docs/en/tutorials/composite-primary-keys.rst +++ b/docs/en/tutorials/composite-primary-keys.rst @@ -63,7 +63,7 @@ and year of production as primary keys: + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> @@ -203,7 +203,7 @@ We keep up the example of an Article with arbitrary attributes, the mapping look + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/docs/en/tutorials/extra-lazy-associations.rst b/docs/en/tutorials/extra-lazy-associations.rst index 456c8c1c5ff..4452d6890a1 100644 --- a/docs/en/tutorials/extra-lazy-associations.rst +++ b/docs/en/tutorials/extra-lazy-associations.rst @@ -65,7 +65,7 @@ switch to extra lazy as shown in these examples: + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/docs/en/tutorials/getting-started.rst b/docs/en/tutorials/getting-started.rst index 605b1a01785..718eac5df05 100644 --- a/docs/en/tutorials/getting-started.rst +++ b/docs/en/tutorials/getting-started.rst @@ -25,7 +25,7 @@ The code of this tutorial is `available on Github + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> @@ -308,6 +314,10 @@ but you only need to choose one. +.. note:: + The YAML driver is deprecated and will be removed in version 3.0. + It is strongly recommended to switch to one of the other mappings. + .. code-block:: yaml # config/yaml/Product.dcm.yml @@ -323,8 +333,8 @@ but you only need to choose one. name: type: string -The top-level ``entity`` definition tag specifies information about -the class and table-name. The primitive type ``Product#name`` is +The top-level ``entity`` definition specifies information about +the class and table name. The primitive type ``Product#name`` is defined as a ``field`` attribute. The ``id`` property is defined with the ``id`` tag. It has a ``generator`` tag nested inside, which specifies that the primary key generation mechanism should automatically @@ -833,7 +843,7 @@ the ``Product`` before: + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> @@ -851,6 +861,10 @@ the ``Product`` before: +.. note:: + The YAML driver is deprecated and will be removed in version 3.0. + It is strongly recommended to switch to one of the other mappings. + .. code-block:: yaml # config/yaml/Bug.dcm.yml @@ -949,7 +963,7 @@ Finally, we'll add metadata mappings for the ``User`` entity. + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> @@ -963,6 +977,10 @@ Finally, we'll add metadata mappings for the ``User`` entity. +.. note:: + The YAML driver is deprecated and will be removed in version 3.0. + It is strongly recommended to switch to one of the other mappings. + .. code-block:: yaml # config/yaml/User.dcm.yml @@ -1486,13 +1504,17 @@ we have to adjust the metadata slightly. + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> +.. note:: + The YAML driver is deprecated and will be removed in version 3.0. + It is strongly recommended to switch to one of the other mappings. + .. code-block:: yaml Bug: diff --git a/docs/en/tutorials/working-with-indexed-associations.rst b/docs/en/tutorials/working-with-indexed-associations.rst index a62d8b34209..0381764bee9 100644 --- a/docs/en/tutorials/working-with-indexed-associations.rst +++ b/docs/en/tutorials/working-with-indexed-associations.rst @@ -107,7 +107,7 @@ The code and mappings for the Market entity looks like this: + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> @@ -193,7 +193,7 @@ here are the code and mappings for it: + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/lib/Doctrine/ORM/AbstractQuery.php b/lib/Doctrine/ORM/AbstractQuery.php index 3ba0dee263d..25a284ceb4c 100644 --- a/lib/Doctrine/ORM/AbstractQuery.php +++ b/lib/Doctrine/ORM/AbstractQuery.php @@ -19,10 +19,12 @@ namespace Doctrine\ORM; +use Doctrine\Common\Persistence\Mapping\MappingException; use Doctrine\Common\Util\ClassUtils; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\ORM\Mapping\MappingException as ORMMappingException; use Doctrine\ORM\Query\Parameter; use Doctrine\ORM\Cache\QueryCacheKey; use Doctrine\DBAL\Cache\QueryCacheProfile; @@ -98,7 +100,7 @@ abstract class AbstractQuery /** * The hydration mode. * - * @var integer + * @var string|int */ protected $_hydrationMode = self::HYDRATE_OBJECT; @@ -410,16 +412,24 @@ public function processParameterValue($value) return $value; } - if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) { + if ($value instanceof Mapping\ClassMetadata) { + return $value->name; + } + + if (! is_object($value)) { + return $value; + } + + try { $value = $this->_em->getUnitOfWork()->getSingleIdentifierValue($value); if ($value === null) { throw ORMInvalidArgumentException::invalidIdentifierBindingEntity(); } - } - - if ($value instanceof Mapping\ClassMetadata) { - return $value->name; + } catch (MappingException | ORMMappingException $e) { + // Silence any mapping exceptions. These can occur if the object in + // question is not a mapped entity, in which case we just don't do + // any preparation on the value. } return $value; @@ -680,8 +690,8 @@ public function setFetchMode($class, $assocName, $fetchMode) /** * Defines the processing mode to be used during hydration / result set transformation. * - * @param integer $hydrationMode Doctrine processing mode to be used during hydration process. - * One of the Query::HYDRATE_* constants. + * @param string|int $hydrationMode Doctrine processing mode to be used during hydration process. + * One of the Query::HYDRATE_* constants. * * @return static This query instance. */ @@ -695,7 +705,7 @@ public function setHydrationMode($hydrationMode) /** * Gets the hydration mode currently used by the query. * - * @return integer + * @return string|int */ public function getHydrationMode() { @@ -707,7 +717,7 @@ public function getHydrationMode() * * Alias for execute(null, $hydrationMode = HYDRATE_OBJECT). * - * @param int $hydrationMode + * @param string|int $hydrationMode * * @return mixed */ @@ -743,7 +753,7 @@ public function getScalarResult() /** * Get exactly one result or null. * - * @param int $hydrationMode + * @param string|int $hydrationMode * * @return mixed * @@ -781,7 +791,7 @@ public function getOneOrNullResult($hydrationMode = null) * If the result is not unique, a NonUniqueResultException is thrown. * If there is no result, a NoResultException is thrown. * - * @param integer $hydrationMode + * @param string|int $hydrationMode * * @return mixed * @@ -875,7 +885,7 @@ public function getHints() * iterate over the result. * * @param ArrayCollection|array|null $parameters The query parameters. - * @param integer|null $hydrationMode The hydration mode to use. + * @param string|int|null $hydrationMode The hydration mode to use. * * @return \Doctrine\ORM\Internal\Hydration\IterableResult */ @@ -899,7 +909,7 @@ public function iterate($parameters = null, $hydrationMode = null) * Executes the query. * * @param ArrayCollection|array|null $parameters Query parameters. - * @param integer|null $hydrationMode Processing mode to be used during the hydration process. + * @param string|int|null $hydrationMode Processing mode to be used during the hydration process. * * @return mixed */ @@ -916,7 +926,7 @@ public function execute($parameters = null, $hydrationMode = null) * Execute query ignoring second level cache. * * @param ArrayCollection|array|null $parameters - * @param integer|null $hydrationMode + * @param string|int|null $hydrationMode * * @return mixed */ @@ -974,7 +984,7 @@ private function executeIgnoreQueryCache($parameters = null, $hydrationMode = nu * Load from second level cache or executes the query and put into cache. * * @param ArrayCollection|array|null $parameters - * @param integer|null $hydrationMode + * @param string|int|null $hydrationMode * * @return mixed */ diff --git a/lib/Doctrine/ORM/EntityManager.php b/lib/Doctrine/ORM/EntityManager.php index 38c90bc5445..c3535148714 100644 --- a/lib/Doctrine/ORM/EntityManager.php +++ b/lib/Doctrine/ORM/EntityManager.php @@ -23,6 +23,7 @@ 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 @@ public function find($entityName, $id, $lockMode = null, $lockVersion = null) { $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 @@ public function find($entityName, $id, $lockMode = null, $lockVersion = null) 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 @@ public function find($entityName, $id, $lockMode = null, $lockVersion = null) 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 @@ public function hasFilters() { 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); + } + break; + case LockMode::PESSIMISTIC_READ: + case LockMode::PESSIMISTIC_WRITE: + if (!$this->getConnection()->isTransactionActive()) { + throw TransactionRequiredException::transactionRequired(); + } + } + } } diff --git a/lib/Doctrine/ORM/EntityManagerInterface.php b/lib/Doctrine/ORM/EntityManagerInterface.php index 3c1c580e935..a423432a162 100644 --- a/lib/Doctrine/ORM/EntityManagerInterface.php +++ b/lib/Doctrine/ORM/EntityManagerInterface.php @@ -174,7 +174,7 @@ public function getReference($entityName, $id); * @param string $entityName The name of the entity type. * @param mixed $identifier The entity identifier. * - * @return object The (partial) entity reference. + * @return object|null The (partial) entity reference. */ public function getPartialReference($entityName, $identifier); @@ -249,7 +249,7 @@ public function getUnitOfWork(); * * @deprecated * - * @param int $hydrationMode + * @param string|int $hydrationMode * * @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator */ @@ -258,7 +258,7 @@ public function getHydrator($hydrationMode); /** * Create a new instance for the given hydration mode. * - * @param int $hydrationMode + * @param string|int $hydrationMode * * @return \Doctrine\ORM\Internal\Hydration\AbstractHydrator * diff --git a/lib/Doctrine/ORM/EntityRepository.php b/lib/Doctrine/ORM/EntityRepository.php index 6be570ba3be..33d7e65c0ab 100644 --- a/lib/Doctrine/ORM/EntityRepository.php +++ b/lib/Doctrine/ORM/EntityRepository.php @@ -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; diff --git a/lib/Doctrine/ORM/Id/AbstractIdGenerator.php b/lib/Doctrine/ORM/Id/AbstractIdGenerator.php index dada71e43ad..9e2e2262514 100644 --- a/lib/Doctrine/ORM/Id/AbstractIdGenerator.php +++ b/lib/Doctrine/ORM/Id/AbstractIdGenerator.php @@ -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); diff --git a/lib/Doctrine/ORM/Internal/CommitOrderCalculator.php b/lib/Doctrine/ORM/Internal/CommitOrderCalculator.php index 34703c6d280..30b9caa8206 100644 --- a/lib/Doctrine/ORM/Internal/CommitOrderCalculator.php +++ b/lib/Doctrine/ORM/Internal/CommitOrderCalculator.php @@ -164,6 +164,17 @@ private function visit($vertex) case self::IN_PROGRESS: if (isset($adjacentVertex->dependencyList[$vertex->hash]) && $adjacentVertex->dependencyList[$vertex->hash]->weight < $edge->weight) { + + // If we have some non-visited dependencies in the in-progress dependency, we + // need to visit them before adding the node. + foreach ($adjacentVertex->dependencyList as $adjacentEdge) { + $adjacentEdgeVertex = $this->nodeList[$adjacentEdge->to]; + + if ($adjacentEdgeVertex->state === self::NOT_VISITED) { + $this->visit($adjacentEdgeVertex); + } + } + $adjacentVertex->state = self::VISITED; $this->sortedNodeList[] = $adjacentVertex->value; diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 0747d4435a0..3b3ecdaa3cb 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -27,7 +27,6 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use ReflectionClass; use Doctrine\Common\Persistence\Mapping\ClassMetadata; -use Doctrine\Common\ClassLoader; use Doctrine\ORM\Cache\CacheException; /** @@ -1025,7 +1024,11 @@ public function validateIdentifier() public function validateAssociations() { foreach ($this->associationMappings as $mapping) { - if ( ! ClassLoader::classExists($mapping['targetEntity']) ) { + if ( + ! class_exists($mapping['targetEntity']) + && ! interface_exists($mapping['targetEntity']) + && ! trait_exists($mapping['targetEntity']) + ) { throw MappingException::invalidTargetEntityClass($mapping['targetEntity'], $this->name, $mapping['fieldName']); } } diff --git a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php index 756399f6d43..ddaff9d4344 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php @@ -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; diff --git a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php index ca270727863..93b697caef6 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -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 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) 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; } @@ -545,7 +549,9 @@ public function loadMetadataForClass($className, ClassMetadata $metadata) if (isset($manyToManyElement->{'order-by'})) { $orderBy = []; foreach ($manyToManyElement->{'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; } diff --git a/lib/Doctrine/ORM/Query.php b/lib/Doctrine/ORM/Query.php index 041ebeebb9f..525aa7a5081 100644 --- a/lib/Doctrine/ORM/Query.php +++ b/lib/Doctrine/ORM/Query.php @@ -656,7 +656,7 @@ public function getMaxResults() * iterated over the result. * * @param ArrayCollection|array|null $parameters The query parameters. - * @param integer $hydrationMode The hydration mode to use. + * @param string|int $hydrationMode The hydration mode to use. * * @return \Doctrine\ORM\Internal\Hydration\IterableResult */ diff --git a/lib/Doctrine/ORM/Query/Expr.php b/lib/Doctrine/ORM/Query/Expr.php index 1373c74a002..25231822d11 100644 --- a/lib/Doctrine/ORM/Query/Expr.php +++ b/lib/Doctrine/ORM/Query/Expr.php @@ -41,10 +41,8 @@ class Expr * // (u.type = ?1) AND (u.role = ?2) * $expr->andX($expr->eq('u.type', ':1'), $expr->eq('u.role', ':2')); * - * @param \Doctrine\ORM\Query\Expr\Comparison | - * \Doctrine\ORM\Query\Expr\Func | - * \Doctrine\ORM\Query\Expr\Orx - * $x Optional clause. Defaults to null, but requires at least one defined when converting to string. + * @param Expr\Comparison|Expr\Func|Expr\Orx|string $x Optional clause. Defaults to null, but requires at least one + * defined when converting to string. * * @return Expr\Andx */ diff --git a/lib/Doctrine/ORM/Query/Expr/Base.php b/lib/Doctrine/ORM/Query/Expr/Base.php index d1303138360..d4b8d3871f1 100644 --- a/lib/Doctrine/ORM/Query/Expr/Base.php +++ b/lib/Doctrine/ORM/Query/Expr/Base.php @@ -56,7 +56,7 @@ abstract class Base protected $parts = []; /** - * @param array $args + * @param mixed $args */ public function __construct($args = []) { diff --git a/lib/Doctrine/ORM/Query/Lexer.php b/lib/Doctrine/ORM/Query/Lexer.php index b889ecfaea6..573e433deab 100644 --- a/lib/Doctrine/ORM/Query/Lexer.php +++ b/lib/Doctrine/ORM/Query/Lexer.php @@ -19,6 +19,8 @@ namespace Doctrine\ORM\Query; +use Doctrine\Common\Lexer\AbstractLexer; + /** * Scans a DQL query for tokens. * @@ -27,7 +29,7 @@ * @author Roman Borschel * @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; diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index 48b13df64aa..d52f3ce1b2e 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -2924,6 +2924,10 @@ public function StringPrimary() case Lexer::T_COALESCE: case Lexer::T_NULLIF: return $this->CaseExpression(); + default: + if ($this->isAggregateFunction($lookaheadType)) { + return $this->AggregateExpression(); + } } $this->syntaxError( diff --git a/lib/Doctrine/ORM/QueryBuilder.php b/lib/Doctrine/ORM/QueryBuilder.php index 4081890dd57..af4d8cd2be6 100644 --- a/lib/Doctrine/ORM/QueryBuilder.php +++ b/lib/Doctrine/ORM/QueryBuilder.php @@ -1027,7 +1027,7 @@ public function leftJoin($join, $alias, $conditionType = null, $condition = null * * * @param string $key The key/field to set. - * @param string $value The value, expression, placeholder, etc. + * @param mixed $value The value, expression, placeholder, etc. * * @return self */ diff --git a/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php b/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php index 5356520c0ee..41a103df4e6 100644 --- a/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php +++ b/lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php @@ -20,7 +20,7 @@ namespace Doctrine\ORM\Tools; use Doctrine\ORM\Mapping\ClassMetadataInfo; -use Doctrine\Common\Util\Inflector; +use Doctrine\Common\Inflector\Inflector; use Doctrine\DBAL\Types\Type; use Symfony\Component\Yaml\Yaml; diff --git a/lib/Doctrine/ORM/Tools/EntityGenerator.php b/lib/Doctrine/ORM/Tools/EntityGenerator.php index cdca27e3b30..aea736511e3 100644 --- a/lib/Doctrine/ORM/Tools/EntityGenerator.php +++ b/lib/Doctrine/ORM/Tools/EntityGenerator.php @@ -20,7 +20,7 @@ namespace Doctrine\ORM\Tools; use Doctrine\Common\Collections\Collection; -use Doctrine\Common\Util\Inflector; +use Doctrine\Common\Inflector\Inflector; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\Mapping\ClassMetadataInfo; diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php index 2d6bf1a73e2..60dabe97336 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php @@ -44,7 +44,7 @@ public function exportClassMetadata(ClassMetadataInfo $metadata) $xml = new SimpleXmlElement(''); + 'xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd" />'); if ($metadata->isMappedSuperclass) { $root = $xml->addChild('mapped-superclass'); diff --git a/lib/Doctrine/ORM/Tools/Pagination/Paginator.php b/lib/Doctrine/ORM/Tools/Pagination/Paginator.php index 250df071f92..0987dfc3492 100644 --- a/lib/Doctrine/ORM/Tools/Pagination/Paginator.php +++ b/lib/Doctrine/ORM/Tools/Pagination/Paginator.php @@ -145,6 +145,7 @@ public function getIterator() $subQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); } else { $this->appendTreeWalker($subQuery, LimitSubqueryWalker::class); + $this->unbindUnusedQueryParams($subQuery); } $subQuery->setFirstResult($offset)->setMaxResults($length); @@ -256,14 +257,20 @@ private function getCountQuery() $countQuery->setResultSetMapping($rsm); } else { $this->appendTreeWalker($countQuery, CountWalker::class); + $this->unbindUnusedQueryParams($countQuery); } $countQuery->setFirstResult(null)->setMaxResults(null); - $parser = new Parser($countQuery); + return $countQuery; + } + + private function unbindUnusedQueryParams(Query $query): void + { + $parser = new Parser($query); $parameterMappings = $parser->parse()->getParameterMappings(); /* @var $parameters \Doctrine\Common\Collections\Collection|\Doctrine\ORM\Query\Parameter[] */ - $parameters = $countQuery->getParameters(); + $parameters = $query->getParameters(); foreach ($parameters as $key => $parameter) { $parameterName = $parameter->getName(); @@ -273,8 +280,6 @@ private function getCountQuery() } } - $countQuery->setParameters($parameters); - - return $countQuery; + $query->setParameters($parameters); } } diff --git a/lib/Doctrine/ORM/Tools/SchemaTool.php b/lib/Doctrine/ORM/Tools/SchemaTool.php index 1950446e7c8..423ed3b5320 100644 --- a/lib/Doctrine/ORM/Tools/SchemaTool.php +++ b/lib/Doctrine/ORM/Tools/SchemaTool.php @@ -45,6 +45,8 @@ */ class SchemaTool { + private const KNOWN_COLUMN_OPTIONS = ['comment', 'unsigned', 'fixed', 'default']; + /** * @var \Doctrine\ORM\EntityManagerInterface */ @@ -467,19 +469,8 @@ private function gatherColumn($class, array $mapping, Table $table) $options['columnDefinition'] = $mapping['columnDefinition']; } - if (isset($mapping['options'])) { - $knownOptions = ['comment', 'unsigned', 'fixed', 'default']; - - foreach ($knownOptions as $knownOption) { - if (array_key_exists($knownOption, $mapping['options'])) { - $options[$knownOption] = $mapping['options'][$knownOption]; - - unset($mapping['options'][$knownOption]); - } - } - - $options['customSchemaOptions'] = $mapping['options']; - } + // the 'default' option can be overwritten here + $options = $this->gatherColumnOptions($mapping) + $options; if ($class->isIdGeneratorIdentity() && $class->getIdentifierFieldNames() == [$mapping['fieldName']]) { $options['autoincrement'] = true; @@ -690,9 +681,7 @@ private function gatherRelationJoinColumns( $columnOptions['notnull'] = ! $joinColumn['nullable']; } - if (isset($fieldMapping['options'])) { - $columnOptions['options'] = $fieldMapping['options']; - } + $columnOptions = $columnOptions + $this->gatherColumnOptions($fieldMapping); if ($fieldMapping['type'] == "string" && isset($fieldMapping['length'])) { $columnOptions['length'] = $fieldMapping['length']; @@ -745,6 +734,23 @@ private function gatherRelationJoinColumns( } } + /** + * @param mixed[] $mapping + * + * @return mixed[] + */ + private function gatherColumnOptions(array $mapping) : array + { + if (! isset($mapping['options'])) { + return []; + } + + $options = array_intersect_key($mapping['options'], array_flip(self::KNOWN_COLUMN_OPTIONS)); + $options['customSchemaOptions'] = array_diff_key($mapping['options'], $options); + + return $options; + } + /** * Drops the database schema for the given classes. * diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 71508f63a7b..4eb7c39db9f 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -2732,7 +2732,7 @@ public function createEntity($className, array $data, &$hints = []) $class->reflFields[$field]->setValue($entity, $data[$field]); $this->originalEntityData[$oid][$field] = $data[$field]; - continue; + break; } $associatedId = []; @@ -2761,7 +2761,7 @@ public function createEntity($className, array $data, &$hints = []) $class->reflFields[$field]->setValue($entity, null); $this->originalEntityData[$oid][$field] = null; - continue; + break; } if ( ! isset($hints['fetchMode'][$class->name][$field])) { diff --git a/lib/Doctrine/ORM/Version.php b/lib/Doctrine/ORM/Version.php index 35941894ee2..0a439da4770 100644 --- a/lib/Doctrine/ORM/Version.php +++ b/lib/Doctrine/ORM/Version.php @@ -35,7 +35,7 @@ class Version /** * Current Doctrine Version */ - const VERSION = '2.6.1-DEV'; + const VERSION = '2.6.3'; /** * Compares a Doctrine version with the current one. diff --git a/tests/Doctrine/Tests/Models/GH7141/GH7141Article.php b/tests/Doctrine/Tests/Models/GH7141/GH7141Article.php new file mode 100644 index 00000000000..5af97c62ef5 --- /dev/null +++ b/tests/Doctrine/Tests/Models/GH7141/GH7141Article.php @@ -0,0 +1,15 @@ +tags = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/GH7316/GH7316Article.php b/tests/Doctrine/Tests/Models/GH7316/GH7316Article.php new file mode 100644 index 00000000000..a832cd70d4c --- /dev/null +++ b/tests/Doctrine/Tests/Models/GH7316/GH7316Article.php @@ -0,0 +1,15 @@ +tags = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/ORM/CommitOrderCalculatorTest.php b/tests/Doctrine/Tests/ORM/CommitOrderCalculatorTest.php index 8c9ec26c44d..c967beb8b62 100644 --- a/tests/Doctrine/Tests/ORM/CommitOrderCalculatorTest.php +++ b/tests/Doctrine/Tests/ORM/CommitOrderCalculatorTest.php @@ -67,6 +67,39 @@ public function testCommitOrdering2() $this->assertSame($correctOrder, $sorted); } + + public function testCommitOrdering3() + { + // this test corresponds to the GH7259Test::testPersistFileBeforeVersion functional test + $class1 = new ClassMetadata(NodeClass1::class); + $class2 = new ClassMetadata(NodeClass2::class); + $class3 = new ClassMetadata(NodeClass3::class); + $class4 = new ClassMetadata(NodeClass4::class); + + $this->_calc->addNode($class1->name, $class1); + $this->_calc->addNode($class2->name, $class2); + $this->_calc->addNode($class3->name, $class3); + $this->_calc->addNode($class4->name, $class4); + + $this->_calc->addDependency($class4->name, $class1->name, 1); + $this->_calc->addDependency($class1->name, $class2->name, 1); + $this->_calc->addDependency($class4->name, $class3->name, 1); + $this->_calc->addDependency($class1->name, $class4->name, 0); + + $sorted = $this->_calc->sort(); + + // There is only multiple valid ordering for this constellation, but + // the class4, class1, class2 ordering is important to break the cycle + // on the nullable link. + $correctOrders = [ + [$class4, $class1, $class2, $class3], + [$class4, $class1, $class3, $class2], + [$class4, $class3, $class1, $class2], + ]; + + // We want to perform a strict comparison of the array + $this->assertContains($sorted, $correctOrders, '', false, true, true); + } } class NodeClass1 {} diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7068Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7068Test.php new file mode 100644 index 00000000000..297d77e0364 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7068Test.php @@ -0,0 +1,43 @@ +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; +} diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7259Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7259Test.php new file mode 100644 index 00000000000..948259815c4 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7259Test.php @@ -0,0 +1,165 @@ +setUpEntitySchema([GH7259Space::class, GH7259File::class, GH7259FileVersion::class, GH7259Feed::class]); + } + + /** + * @group 7259 + */ + public function testPersistFileBeforeVersion() : void + { + $space = new GH7259Space(); + + $this->_em->persist($space); + $this->_em->flush(); + + $feed = new GH7259Feed(); + $feed->space = $space; + + $file = new GH7259File(); + $file->space = $space; + $fileVersion = new GH7259FileVersion(); + $fileVersion->file = $file; + + $this->_em->persist($file); + $this->_em->persist($fileVersion); + $this->_em->persist($feed); + + $this->_em->flush(); + + self::assertNotNull($fileVersion->id); + } + + /** + * @group 7259 + */ + public function testPersistFileAfterVersion() : void + { + $space = new GH7259Space(); + + $this->_em->persist($space); + $this->_em->flush(); + $this->_em->clear(); + + $space = $this->_em->find(GH7259Space::class, $space->id); + + $feed = new GH7259Feed(); + $feed->space = $space; + + $file = new GH7259File(); + $file->space = $space; + $fileVersion = new GH7259FileVersion(); + $fileVersion->file = $file; + + $this->_em->persist($fileVersion); + $this->_em->persist($file); + $this->_em->persist($feed); + + $this->_em->flush(); + + self::assertNotNull($fileVersion->id); + } +} + +/** + * @Entity() + */ +class GH7259File +{ + /** + * @Id + * @GeneratedValue + * @Column(type="integer") + * + * @var int + */ + public $id; + + /** + * @ManyToOne(targetEntity=GH7259Space::class) + * @JoinColumn(nullable=false) + * + * @var GH7259Space|null + */ + public $space; +} + +/** + * @Entity() + */ +class GH7259FileVersion +{ + /** + * @Id + * @GeneratedValue + * @Column(type="integer") + * + * @var int + */ + public $id; + + /** + * @ManyToOne(targetEntity=GH7259File::class) + * @JoinColumn(nullable=false) + * + * @var GH7259File|null + */ + public $file; +} + +/** + * @Entity() + */ +class GH7259Space +{ + /** + * @Id + * @GeneratedValue + * @Column(type="integer") + * + * @var int + */ + public $id; + + /** + * @ManyToOne(targetEntity=GH7259File::class) + * @JoinColumn(nullable=true) + * + * @var GH7259File|null + */ + public $ruleFile; +} + +/** + * @Entity() + */ +class GH7259Feed +{ + /** + * @Id + * @GeneratedValue + * @Column(type="integer") + * + * @var int + */ + public $id; + + /** + * @ManyToOne(targetEntity=GH7259Space::class) + * @JoinColumn(nullable=false) + * + * @var GH7259Space|null + */ + public $space; +} diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7286Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7286Test.php new file mode 100644 index 00000000000..73d20148d9a --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7286Test.php @@ -0,0 +1,135 @@ +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) + ); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7366Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7366Test.php new file mode 100644 index 00000000000..80f5cae723b --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7366Test.php @@ -0,0 +1,75 @@ +setUpEntitySchema( + [ + GH7366Entity::class, + ] + ); + + $this->_em->persist(new GH7366Entity('baz')); + $this->_em->flush(); + $this->_em->clear(); + } + + public function testOptimisticLockNoExceptionOnFind() : void + { + try { + $entity = $this->_em->find(GH7366Entity::class, 1, LockMode::OPTIMISTIC); + } catch (TransactionRequiredException $e) { + self::fail('EntityManager::find() threw TransactionRequiredException with LockMode::OPTIMISTIC'); + } + self::assertEquals('baz', $entity->getName()); + } +} + +/** + * @Entity + */ +class GH7366Entity +{ + /** + * @Id + * @Column(type="integer") + * @GeneratedValue + * @var int + */ + public $id; + + /** + * @Column(type="integer") + * @Version + */ + protected $lockVersion = 1; + + /** + * @Column(length=32) + * @var string + */ + protected $name; + + + public function __construct(string $name) + { + $this->name = $name; + } + + public function getName(): string + { + return $this->name; + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/xml/Doctrine.Tests.Models.OrnementalOrphanRemoval.Person.dcm.xml b/tests/Doctrine/Tests/ORM/Functional/xml/Doctrine.Tests.Models.OrnementalOrphanRemoval.Person.dcm.xml index 6d151af12f8..ff0f103c4cd 100644 --- a/tests/Doctrine/Tests/ORM/Functional/xml/Doctrine.Tests.Models.OrnementalOrphanRemoval.Person.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Functional/xml/Doctrine.Tests.Models.OrnementalOrphanRemoval.Person.dcm.xml @@ -3,7 +3,7 @@ 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 - https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd"> + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Functional/xml/Doctrine.Tests.Models.OrnementalOrphanRemoval.PhoneNumber.dcm.xml b/tests/Doctrine/Tests/ORM/Functional/xml/Doctrine.Tests.Models.OrnementalOrphanRemoval.PhoneNumber.dcm.xml index 2e404254a53..f56c918b420 100644 --- a/tests/Doctrine/Tests/ORM/Functional/xml/Doctrine.Tests.Models.OrnementalOrphanRemoval.PhoneNumber.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Functional/xml/Doctrine.Tests.Models.OrnementalOrphanRemoval.PhoneNumber.dcm.xml @@ -3,7 +3,7 @@ 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 - https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd"> + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php index cc543b8919f..8ff6c0183f5 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/XmlMappingDriverTest.php @@ -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,8 @@ 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\GH7316\GH7316Article; use Doctrine\Tests\Models\ValueObjects\Name; use Doctrine\Tests\Models\ValueObjects\Person; @@ -150,8 +153,8 @@ public function testInvalidMappingFileException() */ public function testValidateXmlSchema($xmlMappingFile) { - $xsdSchemaFile = __DIR__ . '/../../../../../doctrine-mapping.xsd'; - $dom = new \DOMDocument('UTF-8'); + $xsdSchemaFile = __DIR__ . '/../../../../../doctrine-mapping.xsd'; + $dom = new \DOMDocument(); $dom->load($xmlMappingFile); @@ -174,6 +177,38 @@ static public function dataValidSchema() }, $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'] + ); + } + + public function testManyToManyDefaultOrderByAsc() : void + { + $class = new ClassMetadata(GH7316Article::class); + $class->initializeReflection(new RuntimeReflectionService()); + + $driver = $this->_loadDriver(); + $driver->loadMetadataForClass(GH7316Article::class, $class); + + self::assertEquals( + Criteria::ASC, + $class->getMetadataValue('associationMappings')['tags']['orderBy']['position'] + ); + } + /** * @group DDC-889 * @expectedException \Doctrine\Common\Persistence\Mapping\MappingException diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/CatNoId.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/CatNoId.dcm.xml index 6025d350f1e..3f2457bd3d3 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/CatNoId.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/CatNoId.dcm.xml @@ -1,7 +1,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/DDC2429Book.orm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/DDC2429Book.orm.xml index 8640c6f51c4..08e26406bbd 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/DDC2429Book.orm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/DDC2429Book.orm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/DDC2429Novel.orm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/DDC2429Novel.orm.xml index 43ce9428519..5a6f3f89fb8 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/DDC2429Novel.orm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/DDC2429Novel.orm.xml @@ -1,7 +1,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml index 7e7bd5aaa2f..e4b80346c43 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml @@ -1,7 +1,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml index 122a45e6fe9..f91ed311512 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsUser.dcm.xml @@ -3,8 +3,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Cache.City.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Cache.City.dcm.xml index 84b786a7bd7..415302d0a80 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Cache.City.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Cache.City.dcm.xml @@ -1,5 +1,5 @@ - + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyContract.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyContract.dcm.xml index 4fa0c23e1ff..b775e3ccc76 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyContract.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyContract.dcm.xml @@ -3,8 +3,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFixContract.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFixContract.dcm.xml index bd1019d6894..bfa5431fc21 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFixContract.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFixContract.dcm.xml @@ -3,8 +3,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFlexContract.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFlexContract.dcm.xml index 91ef0bb1ce0..21ca4238d1f 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFlexContract.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFlexContract.dcm.xml @@ -3,8 +3,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFlexUltraContract.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFlexUltraContract.dcm.xml index 729bdfda035..381e67571f0 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFlexUltraContract.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyFlexUltraContract.dcm.xml @@ -3,8 +3,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml index 2ddd88a3249..d8db5107341 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Company.CompanyPerson.dcm.xml @@ -3,8 +3,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC117.DDC117Translation.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC117.DDC117Translation.dcm.xml index ec3bc74fd5a..019f201b04a 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC117.DDC117Translation.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC117.DDC117Translation.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.xml index 29b5f1db5cd..fedfeada509 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC1476.DDC1476EntityWithDefaultFieldType.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC2825.ExplicitSchemaAndTable.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC2825.ExplicitSchemaAndTable.dcm.xml index 11bb55706d0..57063fb6ca4 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC2825.ExplicitSchemaAndTable.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC2825.ExplicitSchemaAndTable.dcm.xml @@ -3,7 +3,7 @@ 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 - https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd" + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd" > diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC2825.SchemaAndTableInTableName.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC2825.SchemaAndTableInTableName.dcm.xml index 3a89dd97369..b520f626cf1 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC2825.SchemaAndTableInTableName.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC2825.SchemaAndTableInTableName.dcm.xml @@ -3,7 +3,7 @@ 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 - https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd" + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd" > diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293Address.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293Address.dcm.xml index 39c0f33b2d0..54fbae8b410 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293Address.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293Address.dcm.xml @@ -3,7 +3,7 @@ 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 - https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd"> + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293User.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293User.dcm.xml index bf24c1fd65d..c2d1e44910f 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293User.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293User.dcm.xml @@ -3,7 +3,7 @@ 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 - https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd"> + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293UserPrefixed.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293UserPrefixed.dcm.xml index 1e0df304c05..3988ab32539 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293UserPrefixed.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3293.DDC3293UserPrefixed.dcm.xml @@ -3,7 +3,7 @@ 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 - https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd"> + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579Admin.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579Admin.dcm.xml index 1f92867067e..00695adbb28 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579Admin.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579Admin.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579User.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579User.dcm.xml index 3b6e213f121..a93fb6938ba 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579User.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC3579.DDC3579User.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC5934.DDC5934BaseContract.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC5934.DDC5934BaseContract.dcm.xml index 78a5af6b8d6..07809813177 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC5934.DDC5934BaseContract.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC5934.DDC5934BaseContract.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC5934.DDC5934Contract.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC5934.DDC5934Contract.dcm.xml index bba41b94ec7..4bd3f5af27f 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC5934.DDC5934Contract.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC5934.DDC5934Contract.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.xml index 05e2540eff7..fcc022f7937 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869ChequePayment.dcm.xml @@ -2,7 +2,7 @@ + http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.xml index daf01f03402..bcd02647ece 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869CreditCardPayment.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.xml index be9f760b951..90426f1b096 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC869.DDC869Payment.dcm.xml @@ -2,7 +2,7 @@ + http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml index 4a8935c9a74..86e04112161 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Class.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml index 686bdbfc761..b366cbb6068 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889Entity.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml index 48fa4fb83f6..4b174a393e2 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC889.DDC889SuperClass.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.xml index f4bb4ebce0a..ea6e22fdbda 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Admin.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.xml index 561066f6b83..5ad7a1e1488 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964Guest.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml index 68db74b48e5..83b878840a5 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.DDC964.DDC964User.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.GH7141.GH7141Article.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.GH7141.GH7141Article.dcm.xml new file mode 100644 index 00000000000..34813ab7ef1 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.GH7141.GH7141Article.dcm.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.GH7316.GH7316Article.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.GH7316.GH7316Article.dcm.xml new file mode 100644 index 00000000000..3820cdc9be3 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.GH7316.GH7316Article.dcm.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.xml index 36af855f2a7..5974da2640a 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Generic.SerializationModel.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.ValueObjects.Name.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.ValueObjects.Name.dcm.xml index 97bb6a90eec..0cb3aed27ef 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.ValueObjects.Name.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.ValueObjects.Name.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.ValueObjects.Person.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.ValueObjects.Person.dcm.xml index c2480bca7d2..68752703815 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.ValueObjects.Person.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.ValueObjects.Person.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Animal.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Animal.dcm.xml index a4c4e9bfda7..8ad0e2a6522 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Animal.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Animal.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.CTI.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.CTI.dcm.xml index 14abaef7340..b26ca1089c6 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.CTI.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.CTI.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Comment.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Comment.dcm.xml index 8f02ca852c3..e83232f1a9f 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Comment.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.Comment.dcm.xml @@ -3,7 +3,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.xml index 9f5ad7fac65..a77f2e1bc48 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC1170Entity.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.xml index 82711dc2f89..9a33752340d 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.DDC807Entity.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.SingleTableEntityIncompleteDiscriminatorColumnMapping.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.SingleTableEntityIncompleteDiscriminatorColumnMapping.dcm.xml index 5dffe178d0b..af274cdafdd 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.SingleTableEntityIncompleteDiscriminatorColumnMapping.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.SingleTableEntityIncompleteDiscriminatorColumnMapping.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.SingleTableEntityNoDiscriminatorColumnMapping.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.SingleTableEntityNoDiscriminatorColumnMapping.dcm.xml index 3e03f4498eb..8f2854550eb 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.SingleTableEntityNoDiscriminatorColumnMapping.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.SingleTableEntityNoDiscriminatorColumnMapping.dcm.xml @@ -2,8 +2,8 @@ - + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml index bbf29aeaf70..1fa06126334 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.User.dcm.xml @@ -3,7 +3,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.XMLSLC.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.XMLSLC.dcm.xml index ca8092b50d5..1dec40d7f92 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.XMLSLC.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.ORM.Mapping.XMLSLC.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php b/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php index 064c0a799cb..fe3b298cbf9 100644 --- a/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php +++ b/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php @@ -708,6 +708,13 @@ public function testNewLiteralWithSubselectExpression() { $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 */ diff --git a/tests/Doctrine/Tests/ORM/Query/QueryTest.php b/tests/Doctrine/Tests/ORM/Query/QueryTest.php index 8cceb6c503e..8a3caf66f05 100644 --- a/tests/Doctrine/Tests/ORM/Query/QueryTest.php +++ b/tests/Doctrine/Tests/ORM/Query/QueryTest.php @@ -189,6 +189,25 @@ public function testProcessParameterValueClassMetadata() ); } + public function testProcessParameterValueObject() : void + { + $query = $this->_em->createQuery('SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.user = :user'); + $user = new CmsUser(); + $user->id = 12345; + + self::assertSame( + 12345, + $query->processParameterValue($user) + ); + } + + public function testProcessParameterValueNull() : void + { + $query = $this->_em->createQuery('SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.user = :user'); + + self::assertNull($query->processParameterValue(null)); + } + public function testDefaultQueryHints() { $config = $this->_em->getConfiguration(); diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index 3ce549e1619..b65611217fa 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -823,7 +823,14 @@ public function testLimitAndOffsetFromQueryClass() ->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() diff --git a/tests/Doctrine/Tests/ORM/Tools/Export/XmlClassMetadataExporterTest.php b/tests/Doctrine/Tests/ORM/Tools/Export/XmlClassMetadataExporterTest.php index 424412882eb..4ee7afa8f80 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Export/XmlClassMetadataExporterTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/Export/XmlClassMetadataExporterTest.php @@ -52,7 +52,7 @@ public function testSequenceGenerator() { @@ -89,7 +89,7 @@ public function testFieldOptionsExport() { $expectedFileContent = <<<'XML' - + diff --git a/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml b/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml index 78bac4f5f3f..4092c8574c5 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Tools/Export/xml/Doctrine.Tests.ORM.Tools.Export.User.dcm.xml @@ -3,7 +3,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tests/Doctrine/Tests/ORM/Tools/Pagination/PaginatorTest.php b/tests/Doctrine/Tests/ORM/Tools/Pagination/PaginatorTest.php new file mode 100644 index 00000000000..4b4fc5202bd --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Tools/Pagination/PaginatorTest.php @@ -0,0 +1,119 @@ +connection = $this->getMockBuilder(ConnectionMock::class) + ->setConstructorArgs([[], new DriverMock()]) + ->setMethods(['executeQuery']) + ->getMock() + ; + + $this->em = $this->getMockBuilder(EntityManagerDecorator::class) + ->setConstructorArgs([$this->_getTestEntityManager($this->connection)]) + ->setMethods(['newHydrator']) + ->getMock() + ; + + $this->hydrator = $this->createMock(AbstractHydrator::class); + $this->em->method('newHydrator')->willReturn($this->hydrator); + } + + public function testExtraParametersAreStrippedWhenWalkerRemovingOriginalSelectElementsIsUsed() : void + { + $paramInWhere = 1; + $paramInSubSelect = 2; + $returnedIds = [10]; + + $this->hydrator->method('hydrateAll')->willReturn([$returnedIds]); + + $query = new Query($this->em); + $query->setDQL( + 'SELECT u, + ( + SELECT MAX(a.version) + FROM Doctrine\\Tests\\Models\\CMS\\CmsArticle a + WHERE a.user = u AND 1 = :paramInSubSelect + ) AS HIDDEN max_version + FROM Doctrine\\Tests\\Models\\CMS\\CmsUser u + WHERE u.id = :paramInWhere' + ); + $query->setParameters(['paramInWhere' => $paramInWhere, 'paramInSubSelect' => $paramInSubSelect]); + $paginator = (new Paginator($query, true))->setUseOutputWalkers(false); + + $this->connection->expects($this->exactly(3))->method('executeQuery'); + + $this->connection->expects($this->at(0)) + ->method('executeQuery') + ->with($this->anything(), [$paramInWhere]) + ; + + $this->connection->expects($this->at(1)) + ->method('executeQuery') + ->with($this->anything(), [$paramInWhere]) + ; + + $this->connection->expects($this->at(2)) + ->method('executeQuery') + ->with($this->anything(), [$paramInSubSelect, $paramInWhere, $returnedIds]) + ; + + $paginator->count(); + $paginator->getIterator(); + } + + public function testPaginatorNotCaringAboutExtraParametersWithoutOutputWalkers() : void + { + $this->connection->expects($this->exactly(3))->method('executeQuery'); + + $this->createPaginatorWithExtraParametersWithoutOutputWalkers([])->count(); + $this->createPaginatorWithExtraParametersWithoutOutputWalkers([[10]])->count(); + $this->createPaginatorWithExtraParametersWithoutOutputWalkers([])->getIterator(); + } + + public function testgetIteratorDoesCareAboutExtraParametersWithoutOutputWalkersWhenResultIsNotEmpty() : void + { + $this->connection->expects($this->exactly(1))->method('executeQuery'); + $this->expectException(Query\QueryException::class); + $this->expectExceptionMessage('Too many parameters: the query defines 1 parameters and you bound 2'); + + $this->createPaginatorWithExtraParametersWithoutOutputWalkers([[10]])->getIterator(); + } + + /** + * @param int[][] $willReturnRows + */ + private function createPaginatorWithExtraParametersWithoutOutputWalkers(array $willReturnRows) : Paginator + { + $this->hydrator->method('hydrateAll')->willReturn($willReturnRows); + $this->connection->method('executeQuery')->with($this->anything(), []); + + $query = new Query($this->em); + $query->setDQL('SELECT u FROM Doctrine\\Tests\\Models\\CMS\\CmsUser u'); + $query->setParameters(['paramInWhere' => 1]); + + return (new Paginator($query, true))->setUseOutputWalkers(false); + } +} diff --git a/tests/Doctrine/Tests/ORM/Tools/SchemaToolTest.php b/tests/Doctrine/Tests/ORM/Tools/SchemaToolTest.php index 6750442e8a6..ea520d8fc73 100644 --- a/tests/Doctrine/Tests/ORM/Tools/SchemaToolTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/SchemaToolTest.php @@ -18,6 +18,8 @@ use Doctrine\Tests\Models\CompositeKeyInheritance\JoinedDerivedIdentityClass; use Doctrine\Tests\Models\CompositeKeyInheritance\JoinedDerivedRootClass; use Doctrine\Tests\Models\Forum\ForumAvatar; +use Doctrine\Tests\Models\Forum\ForumBoard; +use Doctrine\Tests\Models\Forum\ForumCategory; use Doctrine\Tests\Models\Forum\ForumUser; use Doctrine\Tests\Models\NullDefault\NullDefaultColumn; use Doctrine\Tests\OrmTestCase; @@ -86,6 +88,44 @@ public function testPassColumnDefinitionToJoinColumn() $this->assertEquals($customColumnDef, $table->getColumn('avatar_id')->getColumnDefinition()); } + /** + * @group 6830 + */ + public function testPassColumnOptionsToJoinColumn() : void + { + $em = $this->_getTestEntityManager(); + $category = $em->getClassMetadata(GH6830Category::class); + $board = $em->getClassMetadata(GH6830Board::class); + + $schemaTool = new SchemaTool($em); + $schema = $schemaTool->getSchemaFromMetadata([$category, $board]); + + self::assertTrue($schema->hasTable('GH6830Category')); + self::assertTrue($schema->hasTable('GH6830Board')); + + $tableCategory = $schema->getTable('GH6830Category'); + $tableBoard = $schema->getTable('GH6830Board'); + + self::assertTrue($tableBoard->hasColumn('category_id')); + + self::assertSame( + $tableCategory->getColumn('id')->getFixed(), + $tableBoard->getColumn('category_id')->getFixed(), + 'Foreign key/join column should have the same value of option `fixed` as the referenced column' + ); + + self::assertEquals( + $tableCategory->getColumn('id')->getCustomSchemaOptions(), + $tableBoard->getColumn('category_id')->getCustomSchemaOptions(), + 'Foreign key/join column should have the same custom options as the referenced column' + ); + + self::assertEquals( + ['collation' => 'latin1_bin', 'foo' => 'bar'], + $tableBoard->getColumn('category_id')->getCustomSchemaOptions() + ); + } + /** * @group DDC-283 */ @@ -322,3 +362,40 @@ class SecondEntity */ public $name; } + +/** + * @Entity + */ +class GH6830Board +{ + /** + * @Id + * @Column(type="integer") + */ + public $id; + + /** + * @ManyToOne(targetEntity=GH6830Category::class, inversedBy="boards") + * @JoinColumn(name="category_id", referencedColumnName="id") + */ + public $category; +} + +/** + * @Entity + */ +class GH6830Category +{ + /** + * @Id + * @Column(type="string", length=8, options={"fixed":true, "collation":"latin1_bin", "foo":"bar"}) + * + * @var string + */ + public $id; + + /** + * @OneToMany(targetEntity=GH6830Board::class, mappedBy="category") + */ + public $boards; +} diff --git a/tools/sandbox/xml/Entities.Address.dcm.xml b/tools/sandbox/xml/Entities.Address.dcm.xml index 7e8dd018340..92475ed233d 100644 --- a/tools/sandbox/xml/Entities.Address.dcm.xml +++ b/tools/sandbox/xml/Entities.Address.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> diff --git a/tools/sandbox/xml/Entities.User.dcm.xml b/tools/sandbox/xml/Entities.User.dcm.xml index e548fd1a77c..4fe7e4c4af0 100644 --- a/tools/sandbox/xml/Entities.User.dcm.xml +++ b/tools/sandbox/xml/Entities.User.dcm.xml @@ -2,7 +2,7 @@ + https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">