Compare commits

..

64 Commits

Author SHA1 Message Date
Alexander Dmitryuk 4c3bd20801 Fix missing setFilterSchemaAssetsExpression in phpdoc (#10776) 2023-06-22 14:36:06 +02:00
Grégoire Paris f2abf6143b Merge pull request #10763 from mpdude/defer-collection-entity-removals-to-post-commit 2023-06-22 14:35:20 +02:00
Grégoire Paris 829d5fbb9f Merge pull request #10780 from greg0ire/avoid-partial 2023-06-22 10:04:27 +02:00
Matthias Pigulla d220494edc Improve documentation on exact behaviour of many-to-many deletion operations 2023-06-21 19:14:55 +02:00
Matthias Pigulla c235901544 Move a check up (continue early) 2023-06-21 19:14:55 +02:00
Matthias Pigulla ba089e551a Avoid unnecessary changes 2023-06-21 19:14:55 +02:00
Matthias Pigulla ee0b3f214d Write tests more concisely 2023-06-21 19:14:55 +02:00
Matthias Pigulla 930fa831b2 Test expected query counts in ManyToManyBasicAssociationTest
When collection updates/join table cleanups do not happen through specialized Entity-/CollectionPersister methods but instead as "plain" updates, we may issue a lot more queries than expected.
2023-06-21 19:14:55 +02:00
Matthias Pigulla 98b404875f Defer removing removed entities from to-many collections until after transaction commit 2023-06-21 19:14:55 +02:00
Grégoire Paris fcc5c106b4 Rely on partial objects less when in tests
Partial objects are deprecated. They were handy to make the generated
SQL more legible, but we should refrain from relying on them.
2023-06-18 18:20:29 +02:00
Grégoire Paris 5132f0deb0 Stop using $message argument
It brings nothing over what PHPUnit now natively does.
2023-06-18 18:16:29 +02:00
Grégoire Paris fe8e313731 Merge pull request #10747 from wtfzdotnet/feature/fix-one-to-many-custom-id-orphan-removal 2023-06-16 10:07:29 +02:00
Grégoire Paris 1adb5c0c70 Merge pull request #10774 from greg0ire/document-dto-in-rsm 2023-06-12 13:52:10 +02:00
Grégoire Paris e5174af669 Document how to produce DTOs with a result set mapping 2023-06-11 18:02:18 +02:00
Vaidas c3106f9fe7 Restore document proxy state to uninitialized on load exception (#10645) 2023-06-09 08:54:22 +02:00
Alexander M. Turek cbf45dd97e PHPStan 1.10.18, Psalm 5.12.0 (#10771) 2023-06-08 16:57:07 +02:00
Michael Roterman 3c0d140e52 OneToManyPersister does not take custom identifier types into account for orphan removal.
In my case a custom doctrine type of Uuid object is converted to string by simply casting it, resulting in a hex DELETE FROM x WHERE id = ? query,
whilst it should've been converted along the way to it's binary representation. This leads to no deletions being made at all as you would expect making use of doctrine custom type's as an identifier.

This commit fixes usage of ramsey/uuid or symfony/uid as custom id types when making use of orphan removal.
2023-06-06 19:51:41 +02:00
Michael Roterman 33675ff4a9 fix: Update baseline and assertions for OneToManyPersister 2023-06-06 18:18:26 +02:00
Nicolas Grekas 3827dd769e Don't call deprecated getSQLResultCasing and usesSequenceEmulatedIdentityColumns when we know the platform (#10759) 2023-06-06 11:27:31 +02:00
Nicolas Grekas 6c9b29f237 Don't call canEmulateSchemas in SchemaTool when possible (#10762) 2023-06-05 21:42:13 +02:00
Grégoire Paris 2afe2dc8af Merge pull request #10758 from Gwemox/partial-revert-enum-id-hash 2023-06-05 11:41:32 +02:00
Thibault Buathier cc3d872b95 revert: transform backed enum to value 2023-06-05 10:58:32 +02:00
Grégoire Paris 65dc154ce5 Merge pull request #10754 from greg0ire/fix-build
Fix build
2023-06-05 08:35:26 +02:00
Grégoire Paris caaa0d6192 Ignore error about get_class($metadata)
This is the result of the contradiction between the phpdoc
(ClassMetadata), and the condition, which guarantees $metadata is not a
ClassMetadata. Relaxing the phpdoc leads to other phpstan issues, about
properties that exist in ClassMetadata but not in
PersistentClassMetadata. The right way to fix this would be to switch
from a deprecation to an exception, but that is not the path we have
taken, and all this will disappear in 3.0.x anyway, so let's not bother.
2023-06-03 20:59:29 +02:00
Grégoire Paris 68d3a63957 Use class name directly
Static analysis points out $this->getName() may return null. But there
is worse: the message mentions a "command class", and getName() is not a
class.
2023-06-03 20:59:29 +02:00
Matthias Pigulla 76b8a215c2 Update docs that name in @Index/@UniqueConstraint is optional (#10748)
Fixes #4283.
2023-06-03 00:14:43 +02:00
Matthias Pigulla b163cea61c Update the FAQ entry on setting MySQL charset and collation for columns (#10746)
Fixes #2986.
2023-06-03 00:13:07 +02:00
Grégoire Paris 4dfbe13897 Merge pull request #10740 from greg0ire/remove-ignore-rule
Remove useless ignore rule
2023-06-02 00:14:27 +02:00
Grégoire Paris b64e1c9b1f Remove useless ignore rule
This is useless since 152f91fa3
2023-06-01 21:03:58 +02:00
Grégoire Paris bf449bef7d Merge pull request #10737 from nicolas-grekas/lexer-deprec 2023-06-01 11:35:50 +02:00
Nicolas Grekas 152f91fa33 Fix deprecations from doctrine/lexer 2023-06-01 11:22:36 +02:00
Grégoire Paris 14d1eb5340 Document pdo_sqlite requirement for tests (#10734) 2023-06-01 08:57:07 +02:00
Grégoire Paris da0998c401 Add missing underscore to RST links (#10731) 2023-05-30 23:00:28 +02:00
Grégoire Paris cc011d8215 Merge pull request #10725 from doctrine/2.14.x
Merge 2.14.x up into 2.15.x
2023-05-24 14:08:21 +02:00
Grégoire Paris d831c126c9 Merge pull request #10643 from htto/bugfix/sti-with-abstract-intermediate
Fix single table inheritance with intermediate abstract class(es)
2023-05-24 11:58:11 +02:00
Grégoire Paris 10eae1a7ff Merge pull request #10722 from phansys/query_single_result_exception
Fix and improve functional test cases expecting `NonUniqueResultException` from `AbstractQuery::getSingleScalarResult()`
2023-05-23 22:46:18 +02:00
Javier Spagnoletti 125e18cf24 Fix and improve functional test cases expecting NonUniqueResultException from AbstractQuery::getSingleScalarResult() 2023-05-23 05:32:38 -03:00
Grégoire Paris 8fba9d6868 Merge pull request #10708 from mbabker/2.15-link-fix 2023-05-16 17:06:17 +02:00
Michael Babker 7f4f1cda71 Correct docs link 2023-05-16 09:38:09 -05:00
Grégoire Paris 1c905b0e0a Merge pull request #10702 from greg0ire/fix-build 2023-05-15 11:53:09 +02:00
Grégoire Paris 7901790b97 Adapt to latest coding standards 2023-05-15 11:42:13 +02:00
Grégoire Paris cef1d2d740 Merge pull request #10666 from MatTheCat/inherited-readonly-properties
Create `ReflectionReadonlyProperty` from their declaring class so their value can be set
2023-05-12 07:50:03 +02:00
Grégoire Paris 8126882305 Merge pull request #10486 from mpdude/fix-to-many-update-on-delete
Fix to-many collections left in dirty state after entities are removed by the UoW
2023-05-12 00:11:56 +02:00
Matthias Pigulla a9513692cb Fix to-many collections left in dirty state after entities are removed by the UoW 2023-05-12 00:02:44 +02:00
Grégoire Paris 52c3d9d82a Merge pull request #10508 from Gwemox/fix-enum-identity
Fix id hash of entity with enum as identifier
2023-05-12 00:00:20 +02:00
MatTheCat 2f46e5a130 Rename test class and method 2023-05-11 09:36:43 +02:00
Mathieu a3fa1d7faa Replace assertions by @doesNotPerformAssertions 2023-05-11 09:33:12 +02:00
MatTheCat c7c57be0c2 Create ReflectionReadonlyProperty from their declaring class so their value can be set 2023-05-11 09:33:12 +02:00
MatTheCat 721794fb9c Add test case 2023-05-11 09:33:12 +02:00
Terence Eden 70477d81e9 Documentation typo (#10686)
The past tense of spin is spun, not "spinned"

https://en.wiktionary.org/wiki/spin#English
2023-05-08 12:22:09 +02:00
Alexander M. Turek 9bc6f5b4ac Support unserializing 2.14 ParserResult instances (#10684) 2023-05-07 20:56:25 +02:00
Grégoire Paris 60c625be17 Upgrade to Psalm 5.11.0 (#10679) 2023-05-05 07:21:05 +02:00
Grégoire Paris 8b0d6a13c2 Merge pull request #10671 from BoShurik/fix-attribute-many-to-many-mapping
Fix attribute ManyToMany mapping
2023-05-04 23:52:47 +02:00
Grégoire Paris a7ac6ff8d9 Merge pull request #10677 from greg0ire/psalm-5-10
Upgrade to Psalm 5.10.0
2023-05-04 23:49:02 +02:00
Grégoire Paris 222d544b0c Upgrade to Psalm 5.10.0 2023-05-04 22:12:31 +02:00
ixitheblue 6f1fd7a81e Fix iteration index initialisation (#10675)
In the code examples of the use of the ``Query#toIterable()`` method, an index ``$i`` is used to control the size of the current batch, which ends when the condition ``($i % $batchSize) === 0`` becomes true.

Because this condition is preceded by ``++$i`` and ``$i`` is initialized to 1, the first batch is actually of size ``$batchSize - 1`` instead of ``$batchSize``.

To solve this, ``$i`` should be initialized to 0 instead of 1.
2023-05-04 14:43:56 +02:00
BoShurik 2af6e4db38 Take into account join columns specifications.
Currently, the AttributeDriver ignores any join column attribute specified on a many to many relationship.
Let's copy code from the AnnotationDriver to fix that.

Fixes #9902
2023-05-04 15:36:29 +03:00
BoShurik b48dafded8 Update doc-block for AttributeDriverTest's fixtures 2023-05-04 15:35:40 +03:00
Grégoire Paris ffe1550a68 Bump version numbers in the README (#10674)
2.15.0 has been released.
2023-05-04 13:44:58 +02:00
Grégoire Paris eef5a1db81 Merge pull request #10668 from stollr/doc_attr_uniqueconstraint
Added doc for the fields parameter of the UniqueConstraint attribute
2023-05-04 08:13:33 +02:00
Grégoire Paris c2d053d185 Update branch metadata (#10672) 2023-05-03 22:41:13 +02:00
stollr 77822d623e Added doc for the fields parameter of the UniqueConstraint attribute 2023-05-03 10:45:07 +02:00
Heiko Przybyl 1ae74b8ec5 Fix single table inheritance with intermediate abstract class(es)
Fixes #10625
2023-04-20 15:37:42 +02:00
Thibault Buathier 09b4a75ed3 Fix id hash of entity with enum as identifier
When an entity have a backed enum as identifier, `UnitOfWork` tries to
cast to string when generating the hash of the id.
This fix calls `->value` when identifier is a `BackedEnum`.
Fixes #10471
Fixes #10334
2023-04-03 17:20:48 +02:00
64 changed files with 1740 additions and 373 deletions
+12 -6
View File
@@ -12,21 +12,27 @@
"upcoming": true
},
{
"name": "2.15",
"branchName": "2.15.x",
"slug": "2.15",
"name": "2.16",
"branchName": "2.16.x",
"slug": "2.16",
"upcoming": true
},
{
"name": "2.14",
"branchName": "2.14.x",
"slug": "2.14",
"name": "2.15",
"branchName": "2.15.x",
"slug": "2.15",
"current": true,
"aliases": [
"current",
"stable"
]
},
{
"name": "2.14",
"branchName": "2.14.x",
"slug": "2.14",
"maintained": false
},
{
"name": "2.13",
"branchName": "2.13.x",
+5
View File
@@ -40,6 +40,11 @@ cd orm
composer install
```
You will also need to enable the PHP extension that provides the SQLite driver
for PDO: `pdo_sqlite`. How to do so depends on your system, but checking that it
is enabled can universally be done with `php -m`: that command should list the
extension.
To run the testsuite against another database, copy the ``phpunit.xml.dist``
to for example ``mysql.phpunit.xml`` and edit the parameters. You can
take a look at the ``ci/github/phpunit`` directory for some examples. Then run:
+11 -11
View File
@@ -1,7 +1,7 @@
| [3.0.x][3.0] | [2.14.x][2.14] | [2.13.x][2.13] |
| [3.0.x][3.0] | [2.16.x][2.16] | [2.15.x][2.15] |
|:----------------:|:----------------:|:----------:|
| [![Build status][3.0 image]][3.0] | [![Build status][2.14 image]][2.14] | [![Build status][2.13 image]][2.13] |
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.14 coverage image]][2.14 coverage] | [![Coverage Status][2.13 coverage image]][2.13 coverage] |
| [![Build status][3.0 image]][3.0] | [![Build status][2.16 image]][2.16] | [![Build status][2.15 image]][2.15] |
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.16 coverage image]][2.16 coverage] | [![Coverage Status][2.15 coverage image]][2.15 coverage] |
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
@@ -22,11 +22,11 @@ without requiring unnecessary code duplication.
[3.0]: https://github.com/doctrine/orm/tree/3.0.x
[3.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.0.x/graph/badge.svg
[3.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.0.x
[2.14 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.14.x
[2.14]: https://github.com/doctrine/orm/tree/2.14.x
[2.14 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.14.x/graph/badge.svg
[2.14 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.14.x
[2.13 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.13.x
[2.13]: https://github.com/doctrine/orm/tree/2.13.x
[2.13 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.13.x/graph/badge.svg
[2.13 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.13.x
[2.16 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.16.x
[2.16]: https://github.com/doctrine/orm/tree/2.16.x
[2.16 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.16.x/graph/badge.svg
[2.16 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.16.x
[2.15 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.15.x
[2.15]: https://github.com/doctrine/orm/tree/2.15.x
[2.15 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.15.x/graph/badge.svg
[2.15 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.15.x
+2 -2
View File
@@ -42,14 +42,14 @@
"doctrine/annotations": "^1.13 || ^2",
"doctrine/coding-standard": "^9.0.2 || ^12.0",
"phpbench/phpbench": "^0.16.10 || ^1.0",
"phpstan/phpstan": "~1.4.10 || 1.10.14",
"phpstan/phpstan": "~1.4.10 || 1.10.18",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
"psr/log": "^1 || ^2 || ^3",
"squizlabs/php_codesniffer": "3.7.2",
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2",
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
"vimeo/psalm": "4.30.0 || 5.9.0"
"vimeo/psalm": "4.30.0 || 5.12.0"
},
"conflict": {
"doctrine/annotations": "<1.13 || >= 3.0"
+2 -2
View File
@@ -545,12 +545,12 @@ has meaning in the SchemaTool schema generation context.
Required attributes:
- **name**: Name of the Index
- **fields**: Array of fields. Exactly one of **fields**, **columns** is required.
- **columns**: Array of columns. Exactly one of **fields**, **columns** is required.
Optional attributes:
- **name**: Name of the Index. If not provided, a generated name will be assigned.
- **options**: Array of platform specific options:
- ``where``: SQL WHERE condition to be used for partial indexes. It will
@@ -1316,12 +1316,12 @@ context.
Required attributes:
- **name**: Name of the Index
- **fields**: Array of fields. Exactly one of **fields**, **columns** is required.
- **columns**: Array of columns. Exactly one of **fields**, **columns** is required.
Optional attributes:
- **name**: Name of the Index. If not provided, a generated name will be assigned.
- **options**: Array of platform specific options:
- ``where``: SQL WHERE condition to be used for partial indexes. It will
+18
View File
@@ -881,6 +881,15 @@ Generated MySQL Schema:
replaced by one-to-many/many-to-one associations between the 3
participating classes.
.. note::
For many-to-many associations, the ORM takes care of managing rows
in the join table connecting both sides. Due to the way it deals
with entity removals, database-level constraints may not work the
way one might intuitively assume. Thus, be sure not to miss the section
on :ref:`join table management <remove_object_many_to_many_join_tables>`.
Many-To-Many, Bidirectional
---------------------------
@@ -1019,6 +1028,15 @@ one is bidirectional.
The MySQL schema is exactly the same as for the Many-To-Many
uni-directional case above.
.. note::
For many-to-many associations, the ORM takes care of managing rows
in the join table connecting both sides. Due to the way it deals
with entity removals, database-level constraints may not work the
way one might intuitively assume. Thus, be sure not to miss the section
on :ref:`join table management <remove_object_many_to_many_join_tables>`.
Owning and Inverse Side on a ManyToMany Association
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+4 -3
View File
@@ -540,13 +540,13 @@ has meaning in the ``SchemaTool`` schema generation context.
Required parameters:
- **name**: Name of the Index
- **fields**: Array of fields. Exactly one of **fields, columns** is required.
- **columns**: Array of columns. Exactly one of **fields, columns** is required.
Optional parameters:
- **name**: Name of the Index. If not provided, a generated name will be assigned.
- **options**: Array of platform specific options:
- ``where``: SQL WHERE condition to be used for partial indexes. It will
@@ -1104,11 +1104,12 @@ context.
Required parameters:
- **name**: Name of the Index
- **columns**: Array of columns.
- **fields**: Array of fields (the names of the properties, used in the entity class).
- **columns**: Array of columns (the names of the columns, used in the schema).
Optional parameters:
- **name**: Name of the Index. If not provided, a generated name will be assigned.
- **options**: Array of platform specific options:
- ``where``: SQL WHERE condition to be used for partial indexes. It will
+2 -2
View File
@@ -86,7 +86,7 @@ with the batching strategy that was already used for bulk inserts:
<?php
$batchSize = 20;
$i = 1;
$i = 0;
$q = $em->createQuery('select u from MyProject\Model\User u');
foreach ($q->toIterable() as $user) {
$user->increaseCredit();
@@ -145,7 +145,7 @@ The following example shows how to do this:
<?php
$batchSize = 20;
$i = 1;
$i = 0;
$q = $em->createQuery('select u from MyProject\Model\User u');
foreach($q->toIterable() as $row) {
$em->remove($row);
+4 -5
View File
@@ -13,11 +13,10 @@ Database Schema
How do I set the charset and collation for MySQL tables?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can't set these values with attributes, annotations or inside yml or
xml mapping files. To make a database work with the default charset and
collation you should configure MySQL to use it as default charset, or
create the database with charset and collation details. This way they
get inherited to all newly created database tables and columns.
In your mapping configuration, the column definition (for example, the
``#[Column]`` attribute) has an ``options`` parameter where you can specify
the ``charset`` and ``collation``. The default values are ``utf8`` and
``utf8_unicode_ci``, respectively.
Entity Classes
--------------
+1 -1
View File
@@ -35,7 +35,7 @@ have to be used.
superclass, since they require the "many" side to hold the foreign
key.
It is, however, possible to use the :doc:```ResolveTargetEntityListener`` <cookbook/resolve-target-entity-listener>`
It is, however, possible to use the :doc:`ResolveTargetEntityListener <cookbook/resolve-target-entity-listener>`
to replace references to a mapped superclass with an entity class at runtime.
As long as there is only one entity subclass inheriting from the mapped
superclass and all references to the mapped superclass are resolved to that
@@ -166,10 +166,10 @@ As long as the results are consistent with what a solution _without_ traits woul
have produced, this is probably fine.
However, to mention known limitations, it is currently not possible to use "class"
level `annotations <https://github.com/doctrine/orm/pull/1517>` or
level `annotations <https://github.com/doctrine/orm/pull/1517>`_ or
`attributes <https://github.com/doctrine/orm/issues/8868>` on traits, and attempts to
improve parser support for traits as `here <https://github.com/doctrine/annotations/pull/102>`
or `there <https://github.com/doctrine/annotations/pull/63>` have been abandoned
improve parser support for traits as `here <https://github.com/doctrine/annotations/pull/102>`_
or `there <https://github.com/doctrine/annotations/pull/63>`_ have been abandoned
due to complexity.
XML mapping configuration probably needs to completely re-configure or otherwise
+34
View File
@@ -250,6 +250,40 @@ The first parameter is the name of the column in the SQL result set
and the second parameter is the result alias under which the value
of the column will be placed in the transformed Doctrine result.
Special case: DTOs
...................
You can also use ``ResultSetMapping`` to map the results of a native SQL
query to a DTO (Data Transfer Object). This is done by adding scalar
results for each argument of the DTO's constructor, then filling the
``newObjectMappings`` property of the ``ResultSetMapping`` with
information about where to map each scalar result:
.. code-block:: php
<?php
$rsm = new ResultSetMapping();
$rsm->addScalarResult('name', 1, 'string');
$rsm->addScalarResult('email', 2, 'string');
$rsm->addScalarResult('city', 3, 'string');
$rsm->newObjectMappings['name'] = [
'className' => CmsUserDTO::class,
'objIndex' => 0, // a result can contain many DTOs, this is the index of the DTO to map to
'argIndex' => 0, // each scalar result can be mapped to a different argument of the DTO constructor
];
$rsm->newObjectMappings['email'] = [
'className' => CmsUserDTO::class,
'objIndex' => 0,
'argIndex' => 1,
];
$rsm->newObjectMappings['city'] = [
'className' => CmsUserDTO::class,
'objIndex' => 0,
'argIndex' => 2,
];
Meta results
~~~~~~~~~~~~
+43 -7
View File
@@ -286,17 +286,53 @@ as follows:
After an entity has been removed, its in-memory state is the same as
before the removal, except for generated identifiers.
Removing an entity will also automatically delete any existing
records in many-to-many join tables that link this entity. The
action taken depends on the value of the ``@joinColumn`` mapping
attribute "onDelete". Either Doctrine issues a dedicated ``DELETE``
statement for records of each join table or it depends on the
foreign key semantics of onDelete="CASCADE".
During the ``EntityManager#flush()`` operation, the removed entity
will also be removed from all collections in entities currently
loaded into memory.
.. _remove_object_many_to_many_join_tables:
Join-table management when removing from many-to-many collections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Regarding existing rows in many-to-many join tables that refer to
an entity being removed, the following applies.
When the entity being removed does not declare the many-to-many association
itself (that is, the many-to-many association is unidirectional and
the entity is on the inverse side), the ORM has no reasonable way to
detect associations targeting the entity's class. Thus, no ORM-level handling
of join-table rows is attempted and database-level constraints apply.
In case of database-level ``ON DELETE RESTRICT`` constraints, the
``EntityManager#flush()`` operation may abort and a ``ConstraintViolationException``
may be thrown. No in-memory collections will be modified in this case.
With ``ON DELETE CASCADE``, the RDBMS will take care of removing rows
from join tables.
When the entity being removed is part of bi-directional many-to-many
association, either as the owning or inverse side, the ORM will
delete rows from join tables before removing the entity itself. That means
database-level ``ON DELETE RESTRICT`` constraints on join tables are not
effective, since the join table rows are removed first. Removal of join table
rows happens through specialized methods in entity and collection persister
classes and take one query per entity and join table. In case the association
uses a ``@JoinColumn`` configuration with ``onDelete="CASCADE"``, instead
of using a dedicated ``DELETE`` query the database-level operation will be
relied upon.
.. note::
In case you rely on database-level ``ON DELETE RESTRICT`` constraints,
be aware that by making many-to-many associations bidirectional the
assumed protection may be lost.
Performance of different deletion strategies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Deleting an object with all its associated objects can be achieved
in multiple ways with very different performance impacts.
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM
will fetch this association. If its a Single association it will
pass this entity to
@@ -22,5 +22,5 @@ In this workflow you would modify the database schema first and then
regenerate the PHP code to use with this schema. You need a flexible
code-generator for this task.
We spinned off a subproject, Doctrine CodeGenerator, that will fill this gap and
We spun off a subproject, Doctrine CodeGenerator, that will fill this gap and
allow you to do *Database First* development.
+2 -2
View File
@@ -322,7 +322,7 @@ data in your storage, and later in your application when the data is loaded agai
.. note::
This method, although very common, is inappropriate for Domain Driven
Design (`DDD <https://en.wikipedia.org/wiki/Domain-driven_design>`)
Design (`DDD <https://en.wikipedia.org/wiki/Domain-driven_design>`_)
where methods should represent real business operations and not simple
property change, And business invariants should be maintained both in the
application state (entities in this case) and in the database, with no
@@ -449,7 +449,7 @@ entity.
.. note::
A `DTO <https://en.wikipedia.org/wiki/Data_transfer_object>` is an object
A `DTO <https://en.wikipedia.org/wiki/Data_transfer_object>`_ is an object
that only carries data without any logic. Its only goal is to be transferred
from one service to another.
A ``DTO`` often represents data sent by a client and that has to be validated,
@@ -14,6 +14,7 @@ use Doctrine\Persistence\Proxy;
use function array_fill_keys;
use function array_keys;
use function array_map;
use function count;
use function is_array;
use function key;
@@ -284,13 +285,17 @@ class ObjectHydrator extends AbstractHydrator
$class = $this->_metadataCache[$className];
if ($class->isIdentifierComposite) {
$idHash = '';
foreach ($class->identifier as $fieldName) {
$idHash .= ' ' . (isset($class->associationMappings[$fieldName])
? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
: $data[$fieldName]);
}
$idHash = UnitOfWork::getIdHashByIdentifier(
array_map(
/** @return mixed */
static function (string $fieldName) use ($data, $class) {
return isset($class->associationMappings[$fieldName])
? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
: $data[$fieldName];
},
$class->identifier
)
);
return $this->_uow->tryGetByIdHash(ltrim($idHash), $class->rootEntityName);
} elseif (isset($class->associationMappings[$class->identifier[0]])) {
@@ -9,7 +9,9 @@ use Doctrine\DBAL\Platforms\DB2Platform;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use function get_class;
use function method_exists;
use function strpos;
use function strtolower;
use function strtoupper;
@@ -26,7 +28,7 @@ trait SQLResultCasing
return strtolower($column);
}
if (method_exists(AbstractPlatform::class, 'getSQLResultCasing')) {
if (strpos(get_class($platform), 'Doctrine\\DBAL\\Platforms\\') !== 0 && method_exists(AbstractPlatform::class, 'getSQLResultCasing')) {
return $platform->getSQLResultCasing($column);
}
@@ -7,6 +7,9 @@ namespace Doctrine\ORM\Mapping;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Platforms;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\Deprecations\Deprecation;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
@@ -621,9 +624,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
case ClassMetadata::GENERATOR_TYPE_IDENTITY:
$sequenceName = null;
$fieldName = $class->identifier ? $class->getSingleIdentifierFieldName() : null;
$platform = $this->getTargetPlatform();
// Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) {
/** @psalm-suppress UndefinedClass, InvalidClass */
if (! $platform instanceof MySQLPlatform && ! $platform instanceof SqlitePlatform && ! $platform instanceof SQLServerPlatform && $platform->usesSequenceEmulatedIdentityColumns()) {
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/issues/8850',
@@ -3862,7 +3862,14 @@ class ClassMetadataInfo implements ClassMetadata
{
$reflectionProperty = $reflService->getAccessibleProperty($class, $field);
if ($reflectionProperty !== null && PHP_VERSION_ID >= 80100 && $reflectionProperty->isReadOnly()) {
$reflectionProperty = new ReflectionReadonlyProperty($reflectionProperty);
$declaringClass = $reflectionProperty->getDeclaringClass()->name;
if ($declaringClass !== $class) {
$reflectionProperty = $reflService->getAccessibleProperty($declaringClass, $field);
}
if ($reflectionProperty !== null) {
$reflectionProperty = new ReflectionReadonlyProperty($reflectionProperty);
}
}
return $reflectionProperty;
@@ -437,6 +437,14 @@ class AttributeDriver extends CompatibilityAnnotationDriver
if ($joinTableAttribute->options) {
$joinTable['options'] = $joinTableAttribute->options;
}
foreach ($joinTableAttribute->joinColumns as $joinColumn) {
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
}
foreach ($joinTableAttribute->inverseJoinColumns as $joinColumn) {
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
}
}
foreach ($this->reader->getPropertyAttributeCollection($property, Mapping\JoinColumn::class) as $joinColumn) {
@@ -196,7 +196,7 @@ class DatabaseDriver implements MappingDriver
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/249',
'Passing an instance of %s to %s is deprecated, please pass a ClassMetadata instance instead.',
'Passing an instance of %s to %s is deprecated, please pass a %s instance instead.',
get_class($metadata),
__METHOD__,
ClassMetadata::class
@@ -989,6 +989,7 @@ class XmlDriver extends FileDriver
$result = [];
// Note: we do not use `simplexml_load_file()` because of https://bugs.php.net/bug.php?id=62577
$xmlElement = simplexml_load_string(file_get_contents($file));
assert($xmlElement !== false);
if (isset($xmlElement->entity)) {
foreach ($xmlElement->entity as $entityElement) {
@@ -16,6 +16,7 @@ use function array_reverse;
use function array_values;
use function assert;
use function implode;
use function is_int;
use function is_string;
/**
@@ -174,16 +175,22 @@ class OneToManyPersister extends AbstractCollectionPersister
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$columns = [];
$parameters = [];
$types = [];
foreach ($targetClass->associationMappings[$mapping['mappedBy']]['joinColumns'] as $joinColumn) {
$columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform);
$parameters[] = $identifier[$sourceClass->getFieldForColumn($joinColumn['referencedColumnName'])];
$types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $sourceClass, $this->em);
}
$statement = 'DELETE FROM ' . $this->quoteStrategy->getTableName($targetClass, $this->platform)
. ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
return $this->conn->executeStatement($statement, $parameters);
$numAffected = $this->conn->executeStatement($statement, $parameters, $types);
assert(is_int($numAffected));
return $numAffected;
}
/**
@@ -247,6 +254,8 @@ class OneToManyPersister extends AbstractCollectionPersister
$this->conn->executeStatement($statement);
assert(is_int($numDeleted));
return $numDeleted;
}
}
@@ -538,7 +538,7 @@ class BasicEntityPersister implements EntityPersister
protected function deleteJoinTableRecords(array $identifier, array $types): void
{
foreach ($this->class->associationMappings as $mapping) {
if ($mapping['type'] !== ClassMetadata::MANY_TO_MANY) {
if ($mapping['type'] !== ClassMetadata::MANY_TO_MANY || isset($mapping['isOnDeleteCascade'])) {
continue;
}
@@ -574,10 +574,6 @@ class BasicEntityPersister implements EntityPersister
$otherKeys[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform);
}
if (isset($mapping['isOnDeleteCascade'])) {
continue;
}
$joinTableName = $this->quoteStrategy->getJoinTableName($association, $this->class, $this->platform);
$this->conn->delete($joinTableName, array_combine($keys, $identifier), $types);
@@ -10,6 +10,9 @@ use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Utility\PersisterHelper;
use function array_flip;
use function array_intersect;
use function array_map;
use function array_unshift;
use function implode;
/**
@@ -145,16 +148,13 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
/** @return string */
protected function getSelectConditionDiscriminatorValueSQL()
{
$values = [];
$values = array_map(
[$this->conn, 'quote'],
array_flip(array_intersect($this->class->discriminatorMap, $this->class->subClasses))
);
if ($this->class->discriminatorValue !== null) { // discriminators can be 0
$values[] = $this->conn->quote($this->class->discriminatorValue);
}
$discrValues = array_flip($this->class->discriminatorMap);
foreach ($this->class->subClasses as $subclassName) {
$values[] = $this->conn->quote($discrValues[$subclassName]);
array_unshift($values, $this->conn->quote($this->class->discriminatorValue));
}
$discColumnName = $this->class->getDiscriminatorColumn()['name'];
+12 -1
View File
@@ -21,6 +21,7 @@ use Doctrine\Persistence\Proxy;
use ReflectionProperty;
use Symfony\Component\VarExporter\ProxyHelper;
use Symfony\Component\VarExporter\VarExporter;
use Throwable;
use function array_flip;
use function str_replace;
@@ -204,7 +205,17 @@ EOPHP;
$identifier = $classMetadata->getIdentifierValues($proxy);
if ($entityPersister->loadById($identifier, $proxy) === null) {
try {
$entity = $entityPersister->loadById($identifier, $proxy);
} catch (Throwable $exception) {
$proxy->__setInitializer($initializer);
$proxy->__setCloner($cloner);
$proxy->__setInitialized(false);
throw $exception;
}
if ($entity === null) {
$proxy->__setInitializer($initializer);
$proxy->__setCloner($cloner);
$proxy->__setInitialized(false);
+4 -4
View File
@@ -582,7 +582,7 @@ class Parser
assert($this->lexer->lookahead !== null);
return in_array(
$this->lexer->lookahead['type'],
$this->lexer->lookahead->type,
[Lexer::T_ALL, Lexer::T_ANY, Lexer::T_SOME],
true
);
@@ -978,7 +978,7 @@ class Parser
$this->match(Lexer::T_IDENTIFIER);
assert($this->lexer->token !== null);
return $this->lexer->token['value'];
return $this->lexer->token->value;
}
$this->match(Lexer::T_ALIASED_NAME);
@@ -989,10 +989,10 @@ class Parser
'doctrine/orm',
'https://github.com/doctrine/orm/issues/8818',
'Short namespace aliases such as "%s" are deprecated and will be removed in Doctrine ORM 3.0.',
$this->lexer->token['value']
$this->lexer->token->value
);
[$namespaceAlias, $simpleClassName] = explode(':', $this->lexer->token['value']);
[$namespaceAlias, $simpleClassName] = explode(':', $this->lexer->token->value);
return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
}
+24
View File
@@ -6,6 +6,8 @@ namespace Doctrine\ORM\Query;
use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
use function sprintf;
/**
* Encapsulates the resulting components from a DQL query parsing process that
* can be serialized.
@@ -14,6 +16,12 @@ use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
*/
class ParserResult
{
private const LEGACY_PROPERTY_MAPPING = [
'sqlExecutor' => '_sqlExecutor',
'resultSetMapping' => '_resultSetMapping',
'parameterMappings' => '_parameterMappings',
];
/**
* The SQL executor used for executing the SQL.
*
@@ -122,4 +130,20 @@ class ParserResult
{
return $this->parameterMappings[$dqlPosition];
}
public function __wakeup(): void
{
$this->__unserialize((array) $this);
}
/** @param array<string, mixed> $data */
public function __unserialize(array $data): void
{
foreach (self::LEGACY_PROPERTY_MAPPING as $property => $legacyProperty) {
$this->$property = $data[sprintf("\0%s\0%s", self::class, $legacyProperty)]
?? $data[sprintf("\0%s\0%s", self::class, $property)]
?? $this->$property
?? null;
}
}
}
@@ -33,7 +33,7 @@ abstract class AbstractEntityManagerCommand extends Command
'doctrine/orm',
'https://github.com/doctrine/orm/issues/8327',
'Not passing EntityManagerProvider as a dependency to command class "%s" is deprecated',
$this->getName()
static::class
);
$helper = $this->getHelper('em');
@@ -73,7 +73,13 @@ in Doctrine 2 and can be used as runtime mapping for the ORM.
by the ORM, you can use a DBAL functionality to filter the tables and sequences down
on a global level:
$config->setFilterSchemaAssetsExpression($regexp);
$config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool {
if ($assetName instanceof AbstractAsset) {
$assetName = $assetName->getName();
}
return !str_starts_with($assetName, 'audit_');
});
EOT
);
}
@@ -33,7 +33,13 @@ Processes the schema and either create it directly on EntityManager Storage Conn
by the ORM, you can use a DBAL functionality to filter the tables and sequences down
on a global level:
$config->setFilterSchemaAssetsExpression($regexp);
$config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool {
if ($assetName instanceof AbstractAsset) {
$assetName = $assetName->getName();
}
return !str_starts_with($assetName, 'audit_');
});
EOT
);
}
@@ -37,7 +37,13 @@ Beware that the complete database is dropped by this command, even tables that a
by the ORM, you can use a DBAL functionality to filter the tables and sequences down
on a global level:
$config->setFilterSchemaAssetsExpression($regexp);
$config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool {
if ($assetName instanceof AbstractAsset) {
$assetName = $assetName->getName();
}
return !str_starts_with($assetName, 'audit_');
});
EOT
);
}
@@ -61,7 +61,13 @@ described by any metadata. Not passing that option is deprecated.
by the ORM, you can use a DBAL functionality to filter the tables and sequences down
on a global level:
$config->setFilterSchemaAssetsExpression($regexp);
$config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool {
if ($assetName instanceof AbstractAsset) {
$assetName = $assetName->getName();
}
return !str_starts_with($assetName, 'audit_');
});
EOT
);
}
+9 -2
View File
@@ -12,6 +12,7 @@ use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\Comparator;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Sequence;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\Visitor\RemoveNamespacedAssets;
use Doctrine\Deprecations\Deprecation;
@@ -406,8 +407,14 @@ class SchemaTool
}
}
if (! $this->platform->supportsSchemas() && ! $this->platform->canEmulateSchemas()) {
$schema->visit(new RemoveNamespacedAssets());
if (! $this->platform->supportsSchemas()) {
$filter = /** @param Sequence|Table $asset */ static function ($asset) use ($schema): bool {
return ! $asset->isInDefaultNamespace($schema->getName());
};
if (array_filter($schema->getSequences() + $schema->getTables(), $filter) && ! $this->platform->canEmulateSchemas()) {
$schema->visit(new RemoveNamespacedAssets());
}
}
if ($eventManager->hasListeners(ToolEvents::postGenerateSchema)) {
+111 -44
View File
@@ -240,6 +240,17 @@ class UnitOfWork implements PropertyChangedListener
*/
private $visitedCollections = [];
/**
* List of collections visited during the changeset calculation that contain to-be-removed
* entities and need to have keys removed post commit.
*
* Indexed by Collection object ID, which also serves as the key in self::$visitedCollections;
* values are the key names that need to be removed.
*
* @psalm-var array<int, array<array-key, true>>
*/
private $pendingCollectionElementRemovals = [];
/**
* The EntityManager that "owns" this UnitOfWork instance.
*
@@ -474,8 +485,15 @@ class UnitOfWork implements PropertyChangedListener
$this->afterTransactionComplete();
// Take new snapshots from visited collections
foreach ($this->visitedCollections as $coll) {
// Unset removed entities from collections, and take new snapshots from
// all visited collections.
foreach ($this->visitedCollections as $coid => $coll) {
if (isset($this->pendingCollectionElementRemovals[$coid])) {
foreach ($this->pendingCollectionElementRemovals[$coid] as $key => $valueIgnored) {
unset($coll[$key]);
}
}
$coll->takeSnapshot();
}
@@ -487,15 +505,16 @@ class UnitOfWork implements PropertyChangedListener
/** @param object|object[]|null $entity */
private function postCommitCleanup($entity): void
{
$this->entityInsertions =
$this->entityUpdates =
$this->entityDeletions =
$this->extraUpdates =
$this->collectionUpdates =
$this->nonCascadedNewDetectedEntities =
$this->collectionDeletions =
$this->visitedCollections =
$this->orphanRemovals = [];
$this->entityInsertions =
$this->entityUpdates =
$this->entityDeletions =
$this->extraUpdates =
$this->collectionUpdates =
$this->nonCascadedNewDetectedEntities =
$this->collectionDeletions =
$this->pendingCollectionElementRemovals =
$this->visitedCollections =
$this->orphanRemovals = [];
if ($entity === null) {
$this->entityChangeSets = $this->scheduledForSynchronization = [];
@@ -916,6 +935,7 @@ class UnitOfWork implements PropertyChangedListener
return;
}
// If this collection is dirty, schedule it for updates
if ($value instanceof PersistentCollection && $value->isDirty()) {
$coid = spl_object_id($value);
@@ -967,10 +987,18 @@ class UnitOfWork implements PropertyChangedListener
case self::STATE_REMOVED:
// Consume the $value as array (it's either an array or an ArrayAccess)
// and remove the element from Collection.
if ($assoc['type'] & ClassMetadata::TO_MANY) {
unset($value[$key]);
if (! ($assoc['type'] & ClassMetadata::TO_MANY)) {
break;
}
$coid = spl_object_id($value);
$this->visitedCollections[$coid] = $value;
if (! isset($this->pendingCollectionElementRemovals[$coid])) {
$this->pendingCollectionElementRemovals[$coid] = [];
}
$this->pendingCollectionElementRemovals[$coid][$key] = true;
break;
case self::STATE_DETACHED:
@@ -1565,14 +1593,8 @@ class UnitOfWork implements PropertyChangedListener
public function addToIdentityMap($entity)
{
$classMetadata = $this->em->getClassMetadata(get_class($entity));
$identifier = $this->entityIdentifiers[spl_object_id($entity)];
if (empty($identifier) || in_array(null, $identifier, true)) {
throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity);
}
$idHash = implode(' ', $identifier);
$className = $classMetadata->rootEntityName;
$idHash = $this->getIdHashByEntity($entity);
$className = $classMetadata->rootEntityName;
if (isset($this->identityMap[$className][$idHash])) {
return false;
@@ -1583,6 +1605,50 @@ class UnitOfWork implements PropertyChangedListener
return true;
}
/**
* Gets the id hash of an entity by its identifier.
*
* @param array<string|int, mixed> $identifier The identifier of an entity
*
* @return string The entity id hash.
*/
final public static function getIdHashByIdentifier(array $identifier): string
{
return implode(
' ',
array_map(
static function ($value) {
if ($value instanceof BackedEnum) {
return $value->value;
}
return $value;
},
$identifier
)
);
}
/**
* Gets the id hash of an entity.
*
* @param object $entity The entity managed by Unit Of Work
*
* @return string The entity id hash.
*/
public function getIdHashByEntity($entity): string
{
$identifier = $this->entityIdentifiers[spl_object_id($entity)];
if (empty($identifier) || in_array(null, $identifier, true)) {
$classMetadata = $this->em->getClassMetadata(get_class($entity));
throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity);
}
return self::getIdHashByIdentifier($identifier);
}
/**
* Gets the state of an entity with regard to the current unit of work.
*
@@ -1685,7 +1751,7 @@ class UnitOfWork implements PropertyChangedListener
{
$oid = spl_object_id($entity);
$classMetadata = $this->em->getClassMetadata(get_class($entity));
$idHash = implode(' ', $this->entityIdentifiers[$oid]);
$idHash = self::getIdHashByIdentifier($this->entityIdentifiers[$oid]);
if ($idHash === '') {
throw ORMInvalidArgumentException::entityHasNoIdentity($entity, 'remove from identity map');
@@ -1755,7 +1821,7 @@ class UnitOfWork implements PropertyChangedListener
}
$classMetadata = $this->em->getClassMetadata(get_class($entity));
$idHash = implode(' ', $this->entityIdentifiers[$oid]);
$idHash = self::getIdHashByIdentifier($this->entityIdentifiers[$oid]);
return isset($this->identityMap[$classMetadata->rootEntityName][$idHash]);
}
@@ -2589,23 +2655,24 @@ 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->nonCascadedNewDetectedEntities =
$this->collectionDeletions =
$this->collectionUpdates =
$this->extraUpdates =
$this->readOnlyObjects =
$this->visitedCollections =
$this->eagerLoadingEntities =
$this->orphanRemovals = [];
$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->pendingCollectionElementRemovals =
$this->visitedCollections =
$this->eagerLoadingEntities =
$this->orphanRemovals = [];
} else {
Deprecation::triggerIfCalledFromOutside(
'doctrine/orm',
@@ -2712,7 +2779,7 @@ class UnitOfWork implements PropertyChangedListener
$class = $this->em->getClassMetadata($className);
$id = $this->identifierFlattener->flattenIdentifier($class, $data);
$idHash = implode(' ', $id);
$idHash = self::getIdHashByIdentifier($id);
if (isset($this->identityMap[$class->rootEntityName][$idHash])) {
$entity = $this->identityMap[$class->rootEntityName][$idHash];
@@ -2871,7 +2938,7 @@ class UnitOfWork implements PropertyChangedListener
// Check identity map first
// FIXME: Can break easily with composite keys if join column values are in
// wrong order. The correct order is the one in ClassMetadata#identifier.
$relatedIdHash = implode(' ', $associatedId);
$relatedIdHash = self::getIdHashByIdentifier($associatedId);
switch (true) {
case isset($this->identityMap[$targetClass->rootEntityName][$relatedIdHash]):
@@ -3156,7 +3223,7 @@ class UnitOfWork implements PropertyChangedListener
*/
public function tryGetById($id, $rootClassName)
{
$idHash = implode(' ', (array) $id);
$idHash = self::getIdHashByIdentifier((array) $id);
return $this->identityMap[$rootClassName][$idHash] ?? false;
}
@@ -3538,7 +3605,7 @@ class UnitOfWork implements PropertyChangedListener
$id1 = $this->entityIdentifiers[$oid1] ?? $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($entity1));
$id2 = $this->entityIdentifiers[$oid2] ?? $this->identifierFlattener->flattenIdentifier($class, $class->getIdentifierValues($entity2));
return $id1 === $id2 || implode(' ', $id1) === implode(' ', $id2);
return $id1 === $id2 || self::getIdHashByIdentifier($id1) === self::getIdHashByIdentifier($id2);
}
/** @throws ORMInvalidArgumentException */
+5
View File
@@ -225,6 +225,11 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php
-
message: "#^Parameter \\#4 \\.\\.\\.\\$args of static method Doctrine\\\\Deprecations\\\\Deprecation\\:\\:trigger\\(\\) expects float\\|int\\|string, false given\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php
-
message: "#^Empty array passed to foreach\\.$#"
count: 1
+3
View File
@@ -10,6 +10,9 @@ parameters:
- '/Call to an undefined method Doctrine\\DBAL\\Connection::createSchemaManager\(\)\./'
# Class name will change in DBAL 3.
- '/^Class Doctrine\\DBAL\\Platforms\\PostgreSQLPlatform not found\.$/'
-
message: '/Doctrine\\DBAL\\Platforms\\MyS(ql|QL)Platform/'
path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
# Forward compatibility for DBAL 3.5
- '/^Call to an undefined method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getAlterSchemaSQL\(\).$/'
+44 -90
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.9.0@8b9ad1eb9e8b7d3101f949291da2b9f7767cd163">
<files psalm-version="5.12.0@f90118cdeacd0088e7215e64c0c99ceca819e176">
<file src="lib/Doctrine/ORM/AbstractQuery.php">
<DeprecatedClass>
<code>IterableResult</code>
@@ -213,6 +213,11 @@
<code>CacheProvider</code>
</MoreSpecificReturnType>
</file>
<file src="lib/Doctrine/ORM/Cache/Region/FileLockRegion.php">
<ArgumentTypeCoercion>
<code><![CDATA[sprintf('%s/*.%s', $this->directory, self::LOCK_EXTENSION)]]></code>
</ArgumentTypeCoercion>
</file>
<file src="lib/Doctrine/ORM/Cache/RegionsConfiguration.php">
<RedundantCastGivenDocblockType>
<code>(int) $defaultLifetime</code>
@@ -437,6 +442,9 @@
<ReferenceReusedFromConfusingScope>
<code>$baseElement</code>
</ReferenceReusedFromConfusingScope>
<UnsupportedPropertyReferenceUsage>
<code><![CDATA[$baseElement =& $this->resultPointers[$parent]]]></code>
</UnsupportedPropertyReferenceUsage>
<UnsupportedReferenceUsage>
<code><![CDATA[$baseElement =& $this->resultPointers[$parent][key($first)]]]></code>
<code><![CDATA[$this->resultPointers[$dqlAlias] =& $coll[key($coll)]]]></code>
@@ -458,6 +466,9 @@
</RedundantConditionGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php">
<InvalidArgument>
<code>$element</code>
</InvalidArgument>
<PossiblyFalseArgument>
<code>$index</code>
</PossiblyFalseArgument>
@@ -610,17 +621,14 @@
<code><![CDATA[$this->subClasses]]></code>
</InvalidPropertyAssignmentValue>
<InvalidReturnStatement>
<code>$mapping</code>
<code>$mapping</code>
<code><![CDATA[$this->reflClass]]></code>
</InvalidReturnStatement>
<InvalidReturnType>
<code>AssociationMapping</code>
<code>FieldMapping</code>
<code>getReflectionClass</code>
</InvalidReturnType>
<LessSpecificReturnStatement>
<code>$cache</code>
<code>$className</code>
<code>$className</code>
<code>$columnNames</code>
@@ -632,8 +640,7 @@
<code>__toString</code>
</MethodSignatureMustProvideReturnType>
<MoreSpecificReturnType>
<code>AssociationMapping</code>
<code>array{usage: int, region: string|null}</code>
<code>FieldMapping</code>
<code>class-string|null</code>
<code><![CDATA[list<string>]]></code>
<code><![CDATA[list<string>]]></code>
@@ -743,12 +750,12 @@
</PossiblyUndefinedArrayOffset>
</file>
<file src="lib/Doctrine/ORM/Mapping/DefaultTypedFieldMapper.php">
<InvalidReturnStatement>
<LessSpecificReturnStatement>
<code>$mapping</code>
</InvalidReturnStatement>
<InvalidReturnType>
</LessSpecificReturnStatement>
<MoreSpecificReturnType>
<code>array</code>
</InvalidReturnType>
</MoreSpecificReturnType>
<PropertyTypeCoercion>
<code>array_merge(self::DEFAULT_TYPED_FIELD_MAPPINGS, $typedFieldMappings)</code>
</PropertyTypeCoercion>
@@ -914,8 +921,18 @@
<InvalidPropertyAssignmentValue>
<code><![CDATA[$metadata->table]]></code>
</InvalidPropertyAssignmentValue>
<InvalidPropertyFetch>
<code><![CDATA[$indexXml->options]]></code>
<code><![CDATA[$uniqueXml->options]]></code>
<code><![CDATA[$xmlRoot->{'discriminator-column'}]]></code>
<code><![CDATA[$xmlRoot->{'discriminator-map'}]]></code>
</InvalidPropertyFetch>
<InvalidReturnStatement>
<code>$mapping</code>
<code><![CDATA[[
'usage' => $usage,
'region' => $region,
]]]></code>
</InvalidReturnStatement>
<InvalidReturnType>
<code>array{
@@ -934,13 +951,8 @@
* columnDefinition?: string,
* options?: array
* }</code>
<code>array{usage: int|null, region?: string}</code>
</InvalidReturnType>
<LessSpecificReturnStatement>
<code><![CDATA[[
'usage' => $usage,
'region' => $region,
]]]></code>
</LessSpecificReturnStatement>
<MissingParamType>
<code>$fileExtension</code>
<code>$locator</code>
@@ -948,40 +960,19 @@
<MoreSpecificImplementedParamType>
<code>$metadata</code>
</MoreSpecificImplementedParamType>
<MoreSpecificReturnType>
<code>array{usage: int|null, region?: string}</code>
</MoreSpecificReturnType>
<NoInterfaceProperties>
<code><![CDATA[$indexXml->options]]></code>
<code><![CDATA[$uniqueXml->options]]></code>
<code><![CDATA[$xmlRoot->{'discriminator-column'}]]></code>
<code><![CDATA[$xmlRoot->{'discriminator-map'}]]></code>
</NoInterfaceProperties>
<PossiblyInvalidPropertyFetch>
<code><![CDATA[$indexXml->options]]></code>
<code><![CDATA[$uniqueXml->options]]></code>
<code><![CDATA[$xmlRoot->{'discriminator-column'}]]></code>
<code><![CDATA[$xmlRoot->{'discriminator-map'}]]></code>
</PossiblyInvalidPropertyFetch>
<RedundantCondition>
<code><![CDATA[isset($xmlRoot->cache)]]></code>
<code><![CDATA[isset($xmlRoot->embedded)]]></code>
<code><![CDATA[isset($xmlRoot->field)]]></code>
<code><![CDATA[isset($xmlRoot->indexes)]]></code>
<code><![CDATA[isset($xmlRoot->options)]]></code>
<code><![CDATA[isset($xmlRoot->{'association-overrides'})]]></code>
<code><![CDATA[isset($xmlRoot->{'attribute-overrides'})]]></code>
<code><![CDATA[isset($xmlRoot->{'entity-listeners'})]]></code>
<code><![CDATA[isset($xmlRoot->{'lifecycle-callbacks'})]]></code>
<code><![CDATA[isset($xmlRoot->{'many-to-many'})]]></code>
<code><![CDATA[isset($xmlRoot->{'many-to-one'})]]></code>
<code><![CDATA[isset($xmlRoot->{'named-native-queries'})]]></code>
<code><![CDATA[isset($xmlRoot->{'named-queries'})]]></code>
<code><![CDATA[isset($xmlRoot->{'one-to-many'})]]></code>
<code><![CDATA[isset($xmlRoot->{'one-to-one'})]]></code>
<code><![CDATA[isset($xmlRoot->{'sql-result-set-mappings'})]]></code>
<code><![CDATA[isset($xmlRoot->{'unique-constraints'})]]></code>
</RedundantCondition>
<PossiblyNullArgument>
<code><![CDATA[$joinColumnElement['options']->children()]]></code>
<code><![CDATA[$option->children()]]></code>
</PossiblyNullArgument>
<PossiblyNullIterator>
<code><![CDATA[$cascadeElement->children()]]></code>
</PossiblyNullIterator>
<TypeDoesNotContainType>
<code><![CDATA[$xmlRoot->getName() === 'embeddable']]></code>
<code><![CDATA[$xmlRoot->getName() === 'entity']]></code>
@@ -989,11 +980,7 @@
</TypeDoesNotContainType>
</file>
<file src="lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php">
<DeprecatedMethod>
<code>addNamedNativeQuery</code>
<code>addNamedQuery</code>
</DeprecatedMethod>
<InvalidArgument>
<ArgumentTypeCoercion>
<code><![CDATA[[
'name' => isset($discrColumn['name']) ? (string) $discrColumn['name'] : null,
'type' => isset($discrColumn['type']) ? (string) $discrColumn['type'] : 'string',
@@ -1001,7 +988,11 @@
'columnDefinition' => isset($discrColumn['columnDefinition']) ? (string) $discrColumn['columnDefinition'] : null,
'enumType' => isset($discrColumn['enumType']) ? (string) $discrColumn['enumType'] : null,
]]]></code>
</InvalidArgument>
</ArgumentTypeCoercion>
<DeprecatedMethod>
<code>addNamedNativeQuery</code>
<code>addNamedQuery</code>
</DeprecatedMethod>
<LessSpecificReturnStatement>
<code><![CDATA[[
'usage' => $usage,
@@ -1038,9 +1029,6 @@
<code>$element</code>
<code>$element</code>
</PossiblyUndefinedMethod>
<PropertyTypeCoercion>
<code><![CDATA[$metadata->table]]></code>
</PropertyTypeCoercion>
<UndefinedInterfaceMethod>
<code>$element</code>
<code>$element</code>
@@ -1256,14 +1244,6 @@
$mapping['indexBy'] => $index,
]]]></code>
</InvalidArrayOffset>
<InvalidReturnStatement>
<code>$numDeleted</code>
<code><![CDATA[$this->conn->executeStatement($statement, $parameters)]]></code>
</InvalidReturnStatement>
<InvalidReturnType>
<code>int</code>
<code>int</code>
</InvalidReturnType>
<PossiblyNullArgument>
<code><![CDATA[$collection->getOwner()]]></code>
<code><![CDATA[$collection->getOwner()]]></code>
@@ -1302,7 +1282,6 @@
</InvalidNullableReturnType>
<LessSpecificReturnStatement>
<code>$newValue</code>
<code>$postInsertIds</code>
<code>[$params, $types]</code>
<code>[$sqlParams, $sqlTypes]</code>
</LessSpecificReturnStatement>
@@ -1310,7 +1289,6 @@
<code>loadAll</code>
</MissingReturnType>
<MoreSpecificReturnType>
<code>executeInserts</code>
<code>expandCriteriaParameters</code>
<code>expandParameters</code>
<code><![CDATA[list<mixed>]]></code>
@@ -1394,12 +1372,6 @@
</MissingReturnType>
</file>
<file src="lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php">
<LessSpecificReturnStatement>
<code>$postInsertIds</code>
</LessSpecificReturnStatement>
<MoreSpecificReturnType>
<code>executeInserts</code>
</MoreSpecificReturnType>
<PossiblyUndefinedArrayOffset>
<code><![CDATA[$assoc['targetToSourceKeyColumns']]]></code>
<code><![CDATA[$mapping['joinColumns']]]></code>
@@ -1937,9 +1909,6 @@
<MethodSignatureMustProvideReturnType>
<code>__toString</code>
</MethodSignatureMustProvideReturnType>
<PropertyTypeCoercion>
<code><![CDATA[$this->parts]]></code>
</PropertyTypeCoercion>
</file>
<file src="lib/Doctrine/ORM/Query/Expr/Comparison.php">
<MethodSignatureMustProvideReturnType>
@@ -2292,10 +2261,6 @@
</file>
<file src="lib/Doctrine/ORM/QueryBuilder.php">
<ArgumentTypeCoercion>
<code>$args</code>
<code>$args</code>
<code>$args</code>
<code>$args</code>
<code><![CDATA[[$rootAlias => $join]]]></code>
<code><![CDATA[[$rootAlias => $join]]]></code>
</ArgumentTypeCoercion>
@@ -2312,17 +2277,9 @@
<InvalidPropertyAssignmentValue>
<code>new ArrayCollection($parameters)</code>
</InvalidPropertyAssignmentValue>
<LessSpecificReturnStatement>
<code>$aliases</code>
<code>$entities</code>
</LessSpecificReturnStatement>
<MethodSignatureMustProvideReturnType>
<code>__toString</code>
</MethodSignatureMustProvideReturnType>
<MoreSpecificReturnType>
<code><![CDATA[list<string>]]></code>
<code><![CDATA[list<string>]]></code>
</MoreSpecificReturnType>
<PossiblyFalseArgument>
<code>$spacePos</code>
<code>$spacePos</code>
@@ -2499,6 +2456,9 @@
</MissingTemplateParam>
</file>
<file src="lib/Doctrine/ORM/Tools/ConvertDoctrine1Schema.php">
<ArgumentTypeCoercion>
<code><![CDATA[$path . '/*.yml']]></code>
</ArgumentTypeCoercion>
<PossiblyUndefinedArrayOffset>
<code><![CDATA[$column['type']]]></code>
</PossiblyUndefinedArrayOffset>
@@ -2621,9 +2581,6 @@
<PossiblyFalseArgument>
<code><![CDATA[$simpleXml->asXML()]]></code>
</PossiblyFalseArgument>
<PossiblyNullReference>
<code>addAttribute</code>
</PossiblyNullReference>
<RedundantCondition>
<code><![CDATA[$field['associationKey']]]></code>
<code><![CDATA[isset($field['associationKey']) && $field['associationKey']]]></code>
@@ -2863,9 +2820,6 @@
<code>unwrap</code>
<code>unwrap</code>
</PossiblyUndefinedMethod>
<PropertyTypeCoercion>
<code><![CDATA[$this->nonCascadedNewDetectedEntities]]></code>
</PropertyTypeCoercion>
<RedundantCondition>
<code><![CDATA[$i >= 0 && $this->entityDeletions]]></code>
<code><![CDATA[$this->entityDeletions]]></code>
+3 -1
View File
@@ -18,6 +18,9 @@
<file name="lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php" />
</ignoreFiles>
</projectFiles>
<enableExtensions>
<extension name="simplexml" />
</enableExtensions>
<issueHandlers>
<DeprecatedClass>
<errorLevel type="suppress">
@@ -79,7 +82,6 @@
<referencedMethod name="Doctrine\DBAL\Platforms\AbstractPlatform::getGuidExpression"/>
<referencedMethod name="Doctrine\DBAL\Platforms\AbstractPlatform::supportsForeignKeyConstraints"/>
<!-- Remove on 3.0.x -->
<referencedMethod name="Doctrine\Common\Lexer\Token::offsetGet"/>
<referencedMethod name="Doctrine\DBAL\Connection::getEventManager"/>
<referencedMethod name="Doctrine\DBAL\Schema\Schema::visit"/>
<referencedMethod name="Doctrine\DBAL\Schema\SchemaDiff::toSaveSql"/>
@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\Models\GH10334;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\ManyToOne;
/**
* @Entity
*/
class GH10334Foo
{
/**
* @var GH10334FooCollection
* @Id
* @ManyToOne(targetEntity="GH10334FooCollection", inversedBy="foos")
* @JoinColumn(name="foo_collection_id", referencedColumnName="id", nullable = false)
* @GeneratedValue
*/
protected $collection;
/**
* @var GH10334ProductTypeId
* @Id
* @Column(type="string", enumType="Doctrine\Tests\Models\GH10334\GH10334ProductTypeId")
*/
protected $productTypeId;
public function __construct(GH10334FooCollection $collection, GH10334ProductTypeId $productTypeId)
{
$this->collection = $collection;
$this->productTypeId = $productTypeId;
}
}
@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\Models\GH10334;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\OneToMany;
/**
* @Entity
*/
class GH10334FooCollection
{
/**
* @var int
* @Id
* @Column(type="integer")
* @GeneratedValue
*/
protected $id;
/**
* @OneToMany(targetEntity="GH10334Foo", mappedBy="collection", cascade={"persist", "remove"})
* @var Collection<GH10334Foo> $foos
*/
private $foos;
public function __construct()
{
$this->foos = new ArrayCollection();
}
/**
* @return Collection<GH10334Foo>
*/
public function getFoos(): Collection
{
return $this->foos;
}
}
@@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\Models\GH10334;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\ManyToOne;
/**
* @Entity
*/
class GH10334Product
{
/**
* @var int
* @Id
* @Column(name="product_id", type="integer")
* @GeneratedValue()
*/
protected $id;
/**
* @var string
* @Column(name="name", type="string")
*/
private $name;
/**
* @var GH10334ProductType $productType
* @ManyToOne(targetEntity="GH10334ProductType", inversedBy="products")
* @JoinColumn(name="product_type_id", referencedColumnName="id", nullable = false)
*/
private $productType;
public function __construct(string $name, GH10334ProductType $productType)
{
$this->name = $name;
$this->productType = $productType;
}
public function getProductType(): GH10334ProductType
{
return $this->productType;
}
public function setProductType(GH10334ProductType $productType): void
{
$this->productType = $productType;
}
}
@@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\Models\GH10334;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\OneToMany;
/**
* @Entity
*/
class GH10334ProductType
{
/**
* @var GH10334ProductTypeId
* @Id
* @Column(type="string", enumType="Doctrine\Tests\Models\GH10334\GH10334ProductTypeId")
*/
protected $id;
/**
* @var float
* @Column(type="float")
*/
private $value;
/**
* @OneToMany(targetEntity="GH10334Product", mappedBy="productType", cascade={"persist", "remove"})
* @var Collection $products
*/
private $products;
public function __construct(GH10334ProductTypeId $id, float $value)
{
$this->id = $id;
$this->value = $value;
$this->products = new ArrayCollection();
}
public function getId(): GH10334ProductTypeId
{
return $this->id;
}
public function addProduct(GH10334Product $product): void
{
$product->setProductType($this);
$this->products->add($product);
}
}
@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\Models\GH10334;
enum GH10334ProductTypeId: string
{
case Jean = 'jean';
case Short = 'short';
}
@@ -0,0 +1,195 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type as DBALType;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\Table;
use Doctrine\Tests\DbalTypes\CustomIdObject;
use Doctrine\Tests\OrmFunctionalTestCase;
use function method_exists;
use function str_replace;
/**
* Functional tests for asserting that orphaned children in a OneToMany relationship get removed with a custom identifier
*
* @group GH10747
*/
final class GH10747Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
if (! DBALType::hasType(GH10747CustomIdObjectHashType::class)) {
DBALType::addType(GH10747CustomIdObjectHashType::class, GH10747CustomIdObjectHashType::class);
}
$this->setUpEntitySchema([GH10747Article::class, GH10747Credit::class]);
}
public function testOrphanedOneToManyDeletesCollection(): void
{
$object = new GH10747Article(
new CustomIdObject('article')
);
$creditOne = new GH10747Credit(
$object,
'credit1'
);
$creditTwo = new GH10747Credit(
$object,
'credit2'
);
$object->setCredits(new ArrayCollection([$creditOne, $creditTwo]));
$this->_em->persist($object);
$this->_em->persist($creditOne);
$this->_em->persist($creditTwo);
$this->_em->flush();
$id = $object->id;
$object2 = $this->_em->find(GH10747Article::class, $id);
$creditThree = new GH10747Credit(
$object2,
'credit3'
);
$object2->setCredits(new ArrayCollection([$creditThree]));
$this->_em->persist($object2);
$this->_em->persist($creditThree);
$this->_em->flush();
$currentDatabaseCredits = $this->_em->createQueryBuilder()
->select('c.id')
->from(GH10747Credit::class, 'c')
->getQuery()
->execute();
self::assertCount(1, $currentDatabaseCredits);
}
}
/**
* @Entity
* @Table
*/
class GH10747Article
{
/**
* @Id
* @Column(type="Doctrine\Tests\ORM\Functional\GH10747CustomIdObjectHashType")
* @var CustomIdObject
*/
public $id;
/**
* @ORM\OneToMany(targetEntity="GH10747Credit", mappedBy="article", orphanRemoval=true)
*
* @var Collection<int, GH10747Credit>
*/
public $credits;
public function __construct(CustomIdObject $id)
{
$this->id = $id;
$this->credits = new ArrayCollection();
}
public function setCredits(Collection $credits): void
{
$this->credits = $credits;
}
/** @return Collection<int, GH10747Credit> */
public function getCredits(): Collection
{
return $this->credits;
}
}
/**
* @Entity
* @Table
*/
class GH10747Credit
{
/**
* @ORM\Column(type="integer")
* @ORM\GeneratedValue()
*
* @Id()
* @var int|null
*/
public $id = null;
/** @var string */
public $name;
/**
* @ORM\ManyToOne(targetEntity="GH10747Article", inversedBy="credits")
*
* @var GH10747Article
*/
public $article;
public function __construct(GH10747Article $article, string $name)
{
$this->article = $article;
$this->name = $name;
}
}
class GH10747CustomIdObjectHashType extends DBALType
{
/**
* {@inheritDoc}
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return $value->id . '_test';
}
/**
* {@inheritDoc}
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return new CustomIdObject(str_replace('_test', '', $value));
}
/**
* {@inheritDoc}
*/
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
if (method_exists($platform, 'getStringTypeDeclarationSQL')) {
return $platform->getStringTypeDeclarationSQL($fieldDeclaration);
}
return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
}
/**
* {@inheritDoc}
*/
public function getName()
{
return self::class;
}
}
@@ -0,0 +1,125 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Tests\OrmFunctionalTestCase;
/**
* @group GH10752
*/
class GH10752Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->setUpEntitySchema([
GH10752Order::class,
GH10752Promotion::class,
]);
}
public function testThrowExceptionWhenRemovingPromotionThatIsInUse(): void
{
if (! $this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) {
self::markTestSkipped('Platform does not support foreign keys.');
}
$order = new GH10752Order();
$promotion = new GH10752Promotion();
$order->addPromotion($promotion);
$this->_em->persist($order);
$this->_em->persist($promotion);
$this->_em->flush();
$this->_em->remove($promotion);
$this->expectException(ForeignKeyConstraintViolationException::class);
$this->_em->flush();
}
public function testThrowExceptionWhenRemovingPromotionThatIsInUseAndOrderIsNotInMemory(): void
{
if (! $this->_em->getConnection()->getDatabasePlatform()->supportsForeignKeyConstraints()) {
self::markTestSkipped('Platform does not support foreign keys.');
}
$order = new GH10752Order();
$promotion = new GH10752Promotion();
$order->addPromotion($promotion);
$this->_em->persist($order);
$this->_em->persist($promotion);
$this->_em->flush();
$this->_em->clear();
$promotion = $this->_em->find(GH10752Promotion::class, $promotion->id);
$this->_em->remove($promotion);
$this->expectException(ForeignKeyConstraintViolationException::class);
$this->_em->flush();
}
}
/**
* @ORM\Entity
*/
class GH10752Order
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*
* @var int
*/
private $id = null;
/**
* @ORM\ManyToMany(targetEntity="GH10752Promotion", cascade={"persist"})
* @ORM\JoinTable(name="order_promotion",
* joinColumns={@ORM\JoinColumn(name="order_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={@ORM\JoinColumn(name="promotion_id", referencedColumnName="id")}
* )
*
* @var Collection
*/
private $promotions;
public function __construct()
{
$this->promotions = new ArrayCollection();
}
public function addPromotion(GH10752Promotion $promotion): void
{
if (! $this->promotions->contains($promotion)) {
$this->promotions->add($promotion);
}
}
}
/**
* @ORM\Entity
*/
class GH10752Promotion
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*
* @var int
*/
public $id = null;
}
@@ -101,6 +101,9 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
//$user->getGroups()->remove(0);
$this->_em->flush();
self::assertFalse($user->getGroups()->isDirty());
$this->_em->clear();
// Reload same user
@@ -141,8 +144,13 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
$user->groups->clear();
$this->getQueryLog()->reset()->enable();
$this->_em->flush();
// Deletions of entire collections happen in a single query
$this->removeTransactionCommandsFromQueryLog();
self::assertQueryCount(1);
// Check that the links in the association table have been deleted
$this->assertGblancoGroupCountIs(0);
}
@@ -212,12 +220,20 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
/** @group DDC-130 */
public function testRemoveUserWithManyGroups(): void
{
$user = $this->addCmsUserGblancoWithGroups(2);
$user = $this->addCmsUserGblancoWithGroups(10);
$userId = $user->getId();
$this->_em->remove($user);
$this->getQueryLog()->reset()->enable();
$this->_em->flush();
// This takes three queries: One to delete all user -> group join table rows for the user,
// one to delete all user -> tags join table rows for the user, and a final one to delete the user itself.
$this->removeTransactionCommandsFromQueryLog();
self::assertQueryCount(3);
$newUser = $this->_em->find(get_class($user), $userId);
self::assertNull($newUser);
}
@@ -225,15 +241,40 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
/** @group DDC-130 */
public function testRemoveGroupWithUser(): void
{
$user = $this->addCmsUserGblancoWithGroups(2);
$user = $this->addCmsUserGblancoWithGroups(5);
$anotherUser = new CmsUser();
$anotherUser->username = 'joe_doe';
$anotherUser->name = 'Joe Doe';
$anotherUser->status = 'QA Engineer';
foreach ($user->getGroups() as $group) {
$anotherUser->addGroup($group);
}
$this->_em->persist($anotherUser);
$this->_em->flush();
foreach ($user->getGroups() as $group) {
$this->_em->remove($group);
}
$this->getQueryLog()->reset()->enable();
$this->_em->flush();
// This takes 5 * 2 queries for each group to be removed, one to remove all join table rows
// for the CmsGroup -> CmsUser inverse side association (for both users at once),
// and one for the group itself.
$this->removeTransactionCommandsFromQueryLog();
self::assertQueryCount(10);
// Changes to in-memory collection have been made and flushed
self::assertCount(0, $user->getGroups());
self::assertFalse($user->getGroups()->isDirty());
$this->_em->clear();
// Changes have been made to the database
$newUser = $this->_em->find(get_class($user), $user->getId());
self::assertCount(0, $newUser->getGroups());
}
@@ -243,7 +284,13 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
$user = $this->addCmsUserGblancoWithGroups(2);
$user->groups = null;
$this->getQueryLog()->reset()->enable();
$this->_em->flush();
// It takes one query to remove all join table rows for the user at once
$this->removeTransactionCommandsFromQueryLog();
self::assertQueryCount(1);
$this->_em->clear();
$newUser = $this->_em->find(get_class($user), $user->getId());
@@ -528,4 +575,15 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
self::assertFalse($user->groups->isInitialized(), 'Post-condition: matching does not initialize collection');
}
private function removeTransactionCommandsFromQueryLog(): void
{
$log = $this->getQueryLog();
foreach ($log->queries as $key => $entry) {
if ($entry['sql'] === '"START TRANSACTION"' || $entry['sql'] === '"COMMIT"') {
unset($log->queries[$key]);
}
}
}
}
@@ -28,17 +28,36 @@ class ManyToManyEventTest extends OrmFunctionalTestCase
$evm->addEventListener(Events::postUpdate, $this->listener);
}
public function testListenerShouldBeNotifiedOnlyWhenUpdating(): void
public function testListenerShouldBeNotifiedWhenNewCollectionEntryAdded(): void
{
$user = $this->createNewValidUser();
$user = $this->createNewValidUser();
$group = new CmsGroup();
$group->name = 'admins';
$this->_em->persist($user);
$this->_em->persist($group);
$this->_em->flush();
self::assertFalse($this->listener->wasNotified);
$user->addGroup($group);
$this->_em->flush();
self::assertTrue($this->listener->wasNotified);
}
public function testListenerShouldBeNotifiedWhenCollectionEntryRemoved(): void
{
$user = $this->createNewValidUser();
$group = new CmsGroup();
$group->name = 'admins';
$user->addGroup($group);
$this->_em->persist($user);
$this->_em->persist($group);
$this->_em->flush();
self::assertFalse($this->listener->wasNotified);
$user->getGroups()->removeElement($group);
$this->_em->flush();
self::assertTrue($this->listener->wasNotified);
@@ -19,6 +19,7 @@ use Doctrine\Tests\Models\CMS\CmsAddress;
use Doctrine\Tests\Models\CMS\CmsEmail;
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\CMS\CmsUserDTO;
use Doctrine\Tests\Models\Company\CompanyContract;
use Doctrine\Tests\Models\Company\CompanyEmployee;
use Doctrine\Tests\Models\Company\CompanyFixContract;
@@ -155,6 +156,77 @@ class NativeQueryTest extends OrmFunctionalTestCase
self::assertSame($phones[0]->getUser(), $users[0]);
}
public function testMappingAsDto(): void
{
$user = new CmsUser();
$user->name = 'Roman';
$user->username = 'romanb';
$user->status = 'dev';
$phone = new CmsPhonenumber();
$phone->phonenumber = 424242;
$user->addPhonenumber($phone);
$email = new CmsEmail();
$email->email = 'fabio.bat.silva@gmail.com';
$user->setEmail($email);
$addr = new CmsAddress();
$addr->country = 'germany';
$addr->zip = 10827;
$addr->city = 'Berlin';
$user->setAddress($addr);
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
$rsm = new ResultSetMapping();
$rsm->addScalarResult('name', 1, 'string');
$rsm->addScalarResult('email', 2, 'string');
$rsm->addScalarResult('city', 3, 'string');
$rsm->newObjectMappings['name'] = [
'className' => CmsUserDTO::class,
'objIndex' => 0,
'argIndex' => 0,
];
$rsm->newObjectMappings['email'] = [
'className' => CmsUserDTO::class,
'objIndex' => 0,
'argIndex' => 1,
];
$rsm->newObjectMappings['city'] = [
'className' => CmsUserDTO::class,
'objIndex' => 0,
'argIndex' => 2,
];
$query = $this->_em->createNativeQuery(
<<<'SQL'
SELECT u.name, e.email, a.city
FROM cms_users u
INNER JOIN cms_phonenumbers p ON u.id = p.user_id
INNER JOIN cms_emails e ON e.id = u.email_id
INNER JOIN cms_addresses a ON u.id = a.user_id
WHERE username = ?
SQL
,
$rsm
);
$query->setParameter(1, 'romanb');
$users = $query->getResult();
self::assertCount(1, $users);
$user = $users[0];
self::assertInstanceOf(CmsUserDTO::class, $user);
self::assertEquals('Roman', $user->name);
self::assertEquals('fabio.bat.silva@gmail.com', $user->email);
self::assertEquals('Berlin', $user->address);
}
public function testJoinedOneToOneNativeQuery(): void
{
$user = new CmsUser();
@@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\Exec\SingleSelectExecutor;
use Doctrine\ORM\Query\ParserResult;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Tests\OrmFunctionalTestCase;
use Generator;
use ReflectionMethod;
use function file_get_contents;
use function serialize;
use function unserialize;
class ParserResultSerializationTest extends OrmFunctionalTestCase
{
protected function setUp(): void
{
$this->useModelSet('company');
parent::setUp();
}
public function testSerializeParserResult(): void
{
$query = $this->_em
->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyEmployee u WHERE u.name = :name');
$parserResult = self::parseQuery($query);
$serialized = serialize($parserResult);
$unserialized = unserialize($serialized);
$this->assertInstanceOf(ParserResult::class, $unserialized);
$this->assertInstanceOf(ResultSetMapping::class, $unserialized->getResultSetMapping());
$this->assertEquals(['name' => [0]], $unserialized->getParameterMappings());
$this->assertInstanceOf(SingleSelectExecutor::class, $unserialized->getSqlExecutor());
}
/**
* @dataProvider provideSerializedSingleSelectResults
*/
public function testUnserializeSingleSelectResult(string $serialized): void
{
$unserialized = unserialize($serialized);
$this->assertInstanceOf(ParserResult::class, $unserialized);
$this->assertInstanceOf(ResultSetMapping::class, $unserialized->getResultSetMapping());
$this->assertEquals(['name' => [0]], $unserialized->getParameterMappings());
$this->assertInstanceOf(SingleSelectExecutor::class, $unserialized->getSqlExecutor());
}
/** @return Generator<string, array{string}> */
public static function provideSerializedSingleSelectResults(): Generator
{
yield '2.14.3' => [file_get_contents(__DIR__ . '/ParserResults/single_select_2_14_3.txt')];
yield '2.15.0' => [file_get_contents(__DIR__ . '/ParserResults/single_select_2_15_0.txt')];
}
private static function parseQuery(Query $query): ParserResult
{
$r = new ReflectionMethod($query, 'parse');
$r->setAccessible(true);
return $r->invoke($query);
}
}
@@ -486,13 +486,35 @@ class QueryTest extends OrmFunctionalTestCase
public function testGetSingleScalarResultThrowsExceptionOnNoResult(): void
{
$this->expectException('Doctrine\ORM\NoResultException');
$this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a')
$this->_em->createQuery('select a.id from Doctrine\Tests\Models\CMS\CmsArticle a')
->getSingleScalarResult();
}
public function testGetSingleScalarResultThrowsExceptionOnSingleRowWithMultipleColumns(): void
{
$user = new CmsUser();
$user->name = 'Javier';
$user->username = 'phansys';
$user->status = 'developer';
$this->_em->persist($user);
$this->_em->flush();
$this->_em->clear();
$this->expectException(NonUniqueResultException::class);
$this->expectExceptionMessage(
'The query returned a row containing multiple columns. Change the query or use a different result function'
. ' like getScalarResult().'
);
$this->_em->createQuery('select u from Doctrine\Tests\Models\CMS\CmsUser u')
->setMaxResults(1)
->getSingleScalarResult();
}
public function testGetSingleScalarResultThrowsExceptionOnNonUniqueResult(): void
{
$this->expectException('Doctrine\ORM\NonUniqueResultException');
$user = new CmsUser();
$user->name = 'Guilherme';
$user->username = 'gblanco';
@@ -515,7 +537,12 @@ class QueryTest extends OrmFunctionalTestCase
$this->_em->flush();
$this->_em->clear();
$this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a')
$this->expectException(NonUniqueResultException::class);
$this->expectExceptionMessage(
'The query returned multiple rows. Change the query or use a different result function like getScalarResult().'
);
$this->_em->createQuery('select a.id from Doctrine\Tests\Models\CMS\CmsArticle a')
->getSingleScalarResult();
}
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional\Ticket\GH10049;
use Doctrine\Tests\OrmFunctionalTestCase;
/**
* @requires PHP 8.1
*/
class GH10049Test extends OrmFunctionalTestCase
{
public function setUp(): void
{
parent::setUp();
$this->createSchemaForModels(
ReadOnlyPropertyOwner::class,
ReadOnlyPropertyInheritor::class
);
}
/**
* @doesNotPerformAssertions
*/
public function testInheritedReadOnlyPropertyValueCanBeSet(): void
{
$child = new ReadOnlyPropertyInheritor(10049);
$this->_em->persist($child);
$this->_em->flush();
$this->_em->clear();
$this->_em->find(ReadOnlyPropertyInheritor::class, 10049);
}
}
@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional\Ticket\GH10049;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class ReadOnlyPropertyInheritor extends ReadOnlyPropertyOwner
{
}
@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional\Ticket\GH10049;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\MappedSuperclass
*/
abstract class ReadOnlyPropertyOwner
{
public function __construct(
/**
* @ORM\Id
* @ORM\Column(type="integer")
*/
public readonly int $id
) {
}
}
@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\Models\GH10334\GH10334Foo;
use Doctrine\Tests\Models\GH10334\GH10334FooCollection;
use Doctrine\Tests\Models\GH10334\GH10334Product;
use Doctrine\Tests\Models\GH10334\GH10334ProductType;
use Doctrine\Tests\Models\GH10334\GH10334ProductTypeId;
use Doctrine\Tests\OrmFunctionalTestCase;
/**
* @group GH10334Test
* @requires PHP 8.1
*/
class GH10334Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->setUpEntitySchema([GH10334FooCollection::class, GH10334Foo::class, GH10334ProductType::class, GH10334Product::class]);
}
public function testTicket(): void
{
$collection = new GH10334FooCollection();
$foo = new GH10334Foo($collection, GH10334ProductTypeId::Jean);
$foo2 = new GH10334Foo($collection, GH10334ProductTypeId::Short);
$this->_em->persist($collection);
$this->_em->persist($foo);
$this->_em->persist($foo2);
$this->_em->flush();
$this->_em->clear();
$result = $this->_em
->getRepository(GH10334FooCollection::class)
->createQueryBuilder('collection')
->leftJoin('collection.foos', 'foo')->addSelect('foo')
->getQuery()
->getResult();
$this->_em
->getRepository(GH10334FooCollection::class)
->createQueryBuilder('collection')
->leftJoin('collection.foos', 'foo')->addSelect('foo')
->getQuery()
->getResult();
$this->assertCount(1, $result);
$this->assertCount(2, $result[0]->getFoos());
}
public function testGetChildWithBackedEnumId(): void
{
$jean = new GH10334ProductType(GH10334ProductTypeId::Jean, 23.5);
$short = new GH10334ProductType(GH10334ProductTypeId::Short, 45.2);
$product = new GH10334Product('Extra Large Blue', $jean);
$jean->addProduct($product);
$this->_em->persist($jean);
$this->_em->persist($short);
$this->_em->persist($product);
$this->_em->flush();
$this->_em->clear();
$entity = $this->_em->find(GH10334Product::class, 1);
self::assertNotNull($entity);
self::assertSame($entity->getProductType()->getId(), GH10334ProductTypeId::Jean);
}
}
@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Tests\OrmFunctionalTestCase;
/**
* @group GH-10625
*/
class GH10625Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->createSchemaForModels(
GH10625Root::class,
GH10625Middle::class,
GH10625Leaf::class
);
}
/**
* @dataProvider queryClasses
*/
public function testLoadFieldsFromAllClassesInHierarchy(string $queryClass): void
{
$entity = new GH10625Leaf();
$this->_em->persist($entity);
$this->_em->flush();
$this->_em->clear();
$loadedEntity = $this->_em->find($queryClass, $entity->id);
self::assertNotNull($loadedEntity);
self::assertInstanceOf(GH10625Leaf::class, $loadedEntity);
}
public static function queryClasses(): array
{
return [
'query via root entity' => [GH10625Root::class],
'query via intermediate entity' => [GH10625Middle::class],
'query via leaf entity' => [GH10625Leaf::class],
];
}
}
/**
* @ORM\Entity
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorMap({ "1": "GH10625Leaf"})
* ^- This DiscriminatorMap contains the single non-abstract Entity class only
*/
abstract class GH10625Root
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*
* @var int
*/
public $id;
}
/**
* @ORM\Entity
*/
abstract class GH10625Middle extends GH10625Root
{
}
/**
* @ORM\Entity
*/
class GH10625Leaf extends GH10625Middle
{
}
@@ -5,11 +5,13 @@ declare(strict_types=1);
namespace Doctrine\Tests\ORM\Mapping;
use Attribute;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
use Doctrine\ORM\Mapping\MappingAttribute;
use Doctrine\Persistence\Mapping\Driver\AnnotationDriver as PersistenceAnnotationDriver;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Tests\ORM\Mapping\Fixtures\AttributeEntityWithNestedJoinColumns;
use stdClass;
use function class_exists;
@@ -123,6 +125,44 @@ class AttributeDriverTest extends MappingDriverTestCase
self::assertTrue(is_subclass_of(AttributeDriver::class, PersistenceAnnotationDriver::class));
}
/**
* @requires PHP 8.1
*/
public function testManyToManyAssociationWithNestedJoinColumns(): void
{
$factory = $this->createClassMetadataFactory();
$metadata = $factory->getMetadataFor(AttributeEntityWithNestedJoinColumns::class);
self::assertEquals(
[
[
'name' => 'assoz_id',
'referencedColumnName' => 'assoz_id',
'unique' => false,
'nullable' => true,
'onDelete' => null,
'columnDefinition' => null,
],
],
$metadata->associationMappings['assoc']['joinTable']['joinColumns']
);
self::assertEquals(
[
[
'name' => 'inverse_assoz_id',
'referencedColumnName' => 'inverse_assoz_id',
'unique' => false,
'nullable' => true,
'onDelete' => null,
'columnDefinition' => null,
],
],
$metadata->associationMappings['assoc']['joinTable']['inverseJoinColumns']
);
}
}
#[ORM\Entity]
@@ -136,7 +176,7 @@ class AttributeEntityWithoutOriginalParents
#[ORM\GeneratedValue]
public $id;
/** @var AttributeEntityWithoutOriginalParents[] */
/** @var Collection<AttributeEntityWithoutOriginalParents> */
#[ORM\ManyToMany(targetEntity: self::class)]
#[ORM\JoinColumn(name: 'assoz_id', referencedColumnName: 'assoz_id')]
#[ORM\InverseJoinColumn(name: 'assoz_id', referencedColumnName: 'assoz_id')]
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Mapping\Fixtures;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class AttributeEntityWithNestedJoinColumns
{
/** @var int */
#[ORM\Id]
#[ORM\Column(type: 'integer')]
#[ORM\GeneratedValue]
public $id;
/** @var Collection<AttributeEntityWithNestedJoinColumns> */
#[ORM\ManyToMany(targetEntity: self::class)]
#[ORM\JoinTable(
name: 'assoc_table',
joinColumns: new ORM\JoinColumn(name: 'assoz_id', referencedColumnName: 'assoz_id'),
inverseJoinColumns: new ORM\JoinColumn(name: 'inverse_assoz_id', referencedColumnName: 'inverse_assoz_id')
)]
public $assoc;
}
@@ -21,6 +21,7 @@ use Doctrine\Tests\Models\Company\CompanyPerson;
use Doctrine\Tests\Models\ECommerce\ECommerceFeature;
use Doctrine\Tests\OrmTestCase;
use Doctrine\Tests\PHPUnitCompatibility\MockBuilderCompatibilityTools;
use Exception;
use ReflectionProperty;
use stdClass;
@@ -145,6 +146,33 @@ class ProxyFactoryTest extends OrmTestCase
self::assertFalse($proxy->__isInitialized());
}
public function testExceptionOnProxyLoadingDoesNotMarkTheProxyAsInitialized(): void
{
$persister = $this
->getMockBuilderWithOnlyMethods(BasicEntityPersister::class, ['load', 'getClassMetadata'])
->disableOriginalConstructor()
->getMock();
$this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
$proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, ['id' => 42]);
assert($proxy instanceof Proxy);
$exception = new Exception('Literally any kind of connection exception');
$persister
->expects(self::atLeastOnce())
->method('load')
->will(self::throwException($exception));
try {
$proxy->getDescription();
self::fail('An exception was expected to be raised');
} catch (Exception $exception) {
}
self::assertFalse($proxy->__isInitialized(), 'The proxy should not be initialized');
}
/** @group DDC-2432 */
public function testFailedProxyCloningDoesNotMarkTheProxyAsInitialized(): void
{
@@ -32,7 +32,6 @@ use Exception;
use function class_exists;
use function get_class;
use function sprintf;
// DBAL 2 compatibility
class_exists('Doctrine\DBAL\Platforms\MySqlPlatform');
@@ -63,8 +62,7 @@ class SelectSqlGenerationTest extends OrmTestCase
$query->setParameter($name, $value);
}
$query->setHint(ORMQuery::HINT_FORCE_PARTIAL_LOAD, true)
->useQueryCache(false);
$query->useQueryCache(false);
foreach ($queryHints as $name => $value) {
$query->setHint($name, $value);
@@ -74,8 +72,7 @@ class SelectSqlGenerationTest extends OrmTestCase
parent::assertEquals(
$sqlToBeConfirmed,
$sqlGenerated,
sprintf('"%s" is not equal to "%s"', $sqlGenerated, $sqlToBeConfirmed)
$sqlGenerated
);
$query->free();
@@ -98,8 +95,7 @@ class SelectSqlGenerationTest extends OrmTestCase
$query->setParameter($name, $value);
}
$query->setHint(ORMQuery::HINT_FORCE_PARTIAL_LOAD, true)
->useQueryCache(false);
$query->useQueryCache(false);
foreach ($queryHints as $name => $value) {
$query->setHint($name, $value);
@@ -117,8 +113,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT c.id FROM Doctrine\Tests\Models\Company\CompanyPerson c JOIN Doctrine\Tests\Models\Company\CompanyPerson r WHERE c.spouse = r AND r.id = 42',
'SELECT c0_.id AS id_0 FROM company_persons c0_ INNER JOIN company_persons c1_ WHERE c0_.spouse_id = c1_.id AND c1_.id = 42',
[ORMQuery::HINT_FORCE_PARTIAL_LOAD => true]
'SELECT c0_.id AS id_0 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id WHERE c0_.spouse_id = c3_.id AND c3_.id = 42'
);
}
@@ -132,8 +127,7 @@ class SelectSqlGenerationTest extends OrmTestCase
*/
$this->assertSqlGeneration(
'SELECT c.id FROM Doctrine\Tests\Models\Company\CompanyPerson c JOIN Doctrine\Tests\Models\Company\CompanyPerson r WHERE c.spouse = r AND r.id = 42',
'SELECT c0_.id AS id_0 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id WHERE c0_.spouse_id = c3_.id AND c3_.id = 42',
[ORMQuery::HINT_FORCE_PARTIAL_LOAD => false]
'SELECT c0_.id AS id_0 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id WHERE c0_.spouse_id = c3_.id AND c3_.id = 42'
);
}
@@ -141,7 +135,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_'
'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_'
);
}
@@ -165,7 +159,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a JOIN a.user u ORDER BY u.name ASC',
'SELECT c0_.id AS id_0, c0_.topic AS topic_1, c0_.text AS text_2, c0_.version AS version_3 FROM cms_articles c0_ INNER JOIN cms_users c1_ ON c0_.user_id = c1_.id ORDER BY c1_.name ASC'
'SELECT c0_.id AS id_0, c0_.topic AS topic_1, c0_.text AS text_2, c0_.version AS version_3, c0_.user_id AS user_id_4 FROM cms_articles c0_ INNER JOIN cms_users c1_ ON c0_.user_id = c1_.id ORDER BY c1_.name ASC'
);
}
@@ -173,7 +167,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT EXISTS (SELECT p.phonenumber FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234)',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE NOT EXISTS (SELECT c1_.phonenumber FROM cms_phonenumbers c1_ WHERE c1_.phonenumber = 1234)'
'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_ WHERE NOT EXISTS (SELECT c1_.phonenumber FROM cms_phonenumbers c1_ WHERE c1_.phonenumber = 1234)'
);
}
@@ -189,7 +183,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE u = p.user',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c1_.phonenumber AS phonenumber_4 FROM cms_users c0_, cms_phonenumbers c1_ WHERE c0_.id = c1_.user_id'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c1_.phonenumber AS phonenumber_4, c0_.email_id AS email_id_5, c1_.user_id AS user_id_6 FROM cms_users c0_, cms_phonenumbers c1_ WHERE c0_.id = c1_.user_id'
);
}
@@ -197,7 +191,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN Doctrine\Tests\Models\CMS\CmsPhonenumber p WITH u = p.user',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c1_.phonenumber AS phonenumber_4 FROM cms_users c0_ INNER JOIN cms_phonenumbers c1_ ON (c0_.id = c1_.user_id)'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c1_.phonenumber AS phonenumber_4, c0_.email_id AS email_id_5, c1_.user_id AS user_id_6 FROM cms_users c0_ INNER JOIN cms_phonenumbers c1_ ON (c0_.id = c1_.user_id)'
);
}
@@ -205,17 +199,17 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e JOIN Doctrine\Tests\Models\Company\CompanyManager m WITH e.id = m.id',
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id INNER JOIN (company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id) ON (c0_.id = c3_.id)'
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c2_.title AS title_5, c0_.discr AS discr_6, c0_.spouse_id AS spouse_id_7, c2_.car_id AS car_id_8 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id INNER JOIN (company_managers c3_ INNER JOIN company_employees c5_ ON c3_.id = c5_.id INNER JOIN company_persons c4_ ON c3_.id = c4_.id) ON (c0_.id = c4_.id)'
);
$this->assertSqlGeneration(
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyManager m WITH e.id = m.id',
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN (company_managers c2_ INNER JOIN company_employees c4_ ON c2_.id = c4_.id INNER JOIN company_persons c3_ ON c2_.id = c3_.id) ON (c0_.id = c3_.id)'
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c2_.title AS title_5, c0_.discr AS discr_6, c0_.spouse_id AS spouse_id_7, c2_.car_id AS car_id_8 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id LEFT JOIN (company_managers c3_ INNER JOIN company_employees c5_ ON c3_.id = c5_.id INNER JOIN company_persons c4_ ON c3_.id = c4_.id) ON (c0_.id = c4_.id)'
);
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c JOIN c.salesPerson s LEFT JOIN Doctrine\Tests\Models\Company\CompanyEvent e WITH s.id = e.id',
'SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6 FROM company_contracts c0_ INNER JOIN company_employees c1_ ON c0_.salesPerson_id = c1_.id LEFT JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_events c3_ ON (c2_.id = c3_.id) WHERE c0_.discr IN (\'fix\', \'flexible\', \'flexultra\')'
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6, c0_.salesPerson_id AS salesPerson_id_7 FROM company_contracts c0_ INNER JOIN company_employees c1_ ON c0_.salesPerson_id = c1_.id LEFT JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_managers c3_ ON c1_.id = c3_.id LEFT JOIN (company_events c4_ LEFT JOIN company_auctions c5_ ON c4_.id = c5_.id LEFT JOIN company_raffles c6_ ON c4_.id = c6_.id) ON (c2_.id = c4_.id) WHERE c0_.discr IN ('fix', 'flexible', 'flexultra')"
);
}
@@ -223,7 +217,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.phonenumbers p',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c1_.phonenumber AS phonenumber_4 FROM cms_users c0_ INNER JOIN cms_phonenumbers c1_ ON c0_.id = c1_.user_id'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c1_.phonenumber AS phonenumber_4, c0_.email_id AS email_id_5, c1_.user_id AS user_id_6 FROM cms_users c0_ INNER JOIN cms_phonenumbers c1_ ON c0_.id = c1_.user_id'
);
}
@@ -231,7 +225,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u, a FROM Doctrine\Tests\Models\Forum\ForumUser u JOIN u.avatar a',
'SELECT f0_.id AS id_0, f0_.username AS username_1, f1_.id AS id_2 FROM forum_users f0_ INNER JOIN forum_avatars f1_ ON f0_.avatar_id = f1_.id'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f1_.id AS id_2, f0_.avatar_id AS avatar_id_3 FROM forum_users f0_ INNER JOIN forum_avatars f1_ ON f0_.avatar_id = f1_.id'
);
}
@@ -275,7 +269,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u ORDER BY u.id',
'SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ ORDER BY f0_.id ASC'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ ORDER BY f0_.id ASC'
);
}
@@ -283,7 +277,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u ORDER BY u.id asc',
'SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ ORDER BY f0_.id ASC'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ ORDER BY f0_.id ASC'
);
}
@@ -291,7 +285,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u ORDER BY u.id desc',
'SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ ORDER BY f0_.id DESC'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ ORDER BY f0_.id DESC'
);
}
@@ -299,7 +293,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u ORDER BY LENGTH(u.username) + LENGTH(u.username) asc',
'SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ ORDER BY LENGTH(f0_.username) + LENGTH(f0_.username) ASC'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ ORDER BY LENGTH(f0_.username) + LENGTH(f0_.username) ASC'
);
}
@@ -347,7 +341,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.id = ?1',
'SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ WHERE f0_.id = ?'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ WHERE f0_.id = ?'
);
}
@@ -355,7 +349,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.username = :name',
'SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ WHERE f0_.username = ?'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ WHERE f0_.username = ?'
);
}
@@ -363,7 +357,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'select u from Doctrine\Tests\Models\Forum\ForumUser u where u.username = :name and u.username = :name2',
'SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ WHERE f0_.username = ? AND f0_.username = ?'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ WHERE f0_.username = ? AND f0_.username = ?'
);
}
@@ -371,7 +365,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'select u from Doctrine\Tests\Models\Forum\ForumUser u where (u.username = :name OR u.username = :name2) AND u.id = :id',
'SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ WHERE (f0_.username = ? OR f0_.username = ?) AND f0_.id = ?'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ WHERE (f0_.username = ? OR f0_.username = ?) AND f0_.id = ?'
);
}
@@ -396,7 +390,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE ((c0_.id + 5000) * c0_.id + 3) < 10000000'
'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_ WHERE ((c0_.id + 5000) * c0_.id + 3) < 10000000'
);
}
@@ -404,7 +398,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a JOIN a.user u2 WHERE u.id = u2.id',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c1_.id AS id_4, c1_.topic AS topic_5, c1_.text AS text_6, c1_.version AS version_7 FROM cms_users c0_, cms_articles c1_ INNER JOIN cms_users c2_ ON c1_.user_id = c2_.id WHERE c0_.id = c2_.id'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c1_.id AS id_4, c1_.topic AS topic_5, c1_.text AS text_6, c1_.version AS version_7, c0_.email_id AS email_id_8, c1_.user_id AS user_id_9 FROM cms_users c0_, cms_articles c1_ INNER JOIN cms_users c2_ ON c1_.user_id = c2_.id WHERE c0_.id = c2_.id'
);
}
@@ -412,7 +406,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a WHERE u.id = a.user',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c1_.id AS id_4, c1_.topic AS topic_5, c1_.text AS text_6, c1_.version AS version_7 FROM cms_users c0_, cms_articles c1_ WHERE c0_.id = c1_.user_id'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c1_.id AS id_4, c1_.topic AS topic_5, c1_.text AS text_6, c1_.version AS version_7, c0_.email_id AS email_id_8, c1_.user_id AS user_id_9 FROM cms_users c0_, cms_articles c1_ WHERE c0_.id = c1_.user_id'
);
}
@@ -433,11 +427,11 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a WITH a.topic LIKE '%foo%'",
"SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic LIKE '%foo%')"
"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_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic LIKE '%foo%')"
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a WITH a.topic LIKE '%foo%'",
"SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ INNER JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic LIKE '%foo%')"
"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_ INNER JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic LIKE '%foo%')"
);
}
@@ -511,7 +505,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyEmployee',
"SELECT c0_.id AS id_0, c0_.name AS name_1, c0_.discr AS discr_2 FROM company_persons c0_ WHERE c0_.discr IN ('manager', 'employee')"
"SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.title AS title_2, c2_.salary AS salary_3, c2_.department AS department_4, c2_.startDate AS startDate_5, c0_.discr AS discr_6, c0_.spouse_id AS spouse_id_7, c1_.car_id AS car_id_8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE c0_.discr IN ('manager', 'employee')"
);
}
@@ -520,7 +514,7 @@ class SelectSqlGenerationTest extends OrmTestCase
// This also uses FQCNs starting with or without a backslash in the INSTANCE OF parameter
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF (Doctrine\Tests\Models\Company\CompanyEmployee, \Doctrine\Tests\Models\Company\CompanyManager)',
"SELECT c0_.id AS id_0, c0_.name AS name_1, c0_.discr AS discr_2 FROM company_persons c0_ WHERE c0_.discr IN ('manager', 'employee')"
"SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.title AS title_2, c2_.salary AS salary_3, c2_.department AS department_4, c2_.startDate AS startDate_5, c0_.discr AS discr_6, c0_.spouse_id AS spouse_id_7, c1_.car_id AS car_id_8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE c0_.discr IN ('manager', 'employee')"
);
}
@@ -529,7 +523,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF \Doctrine\Tests\Models\Company\CompanyEmployee',
"SELECT c0_.id AS id_0, c0_.name AS name_1, c0_.discr AS discr_2 FROM company_persons c0_ WHERE c0_.discr IN ('manager', 'employee')"
"SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.title AS title_2, c2_.salary AS salary_3, c2_.department AS department_4, c2_.startDate AS startDate_5, c0_.discr AS discr_6, c0_.spouse_id AS spouse_id_7, c1_.car_id AS car_id_8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE c0_.discr IN ('manager', 'employee')"
);
}
@@ -546,7 +540,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Company\CompanyEmployee u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyManager',
"SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c0_.discr AS discr_5 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id WHERE c0_.discr IN ('manager')"
"SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c2_.title AS title_5, c0_.discr AS discr_6, c0_.spouse_id AS spouse_id_7, c2_.car_id AS car_id_8 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id WHERE c0_.discr IN ('manager')"
);
}
@@ -554,7 +548,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Company\CompanyManager u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyManager',
"SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c2_.title AS title_5, c0_.discr AS discr_6 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id WHERE c0_.discr IN ('manager')"
"SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c2_.title AS title_5, c0_.discr AS discr_6, c0_.spouse_id AS spouse_id_7, c2_.car_id AS car_id_8 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id WHERE c0_.discr IN ('manager')"
);
}
@@ -562,7 +556,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF ?1',
'SELECT c0_.id AS id_0, c0_.name AS name_1, c0_.discr AS discr_2 FROM company_persons c0_ WHERE c0_.discr IN (?)',
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.title AS title_2, c2_.salary AS salary_3, c2_.department AS department_4, c2_.startDate AS startDate_5, c0_.discr AS discr_6, c0_.spouse_id AS spouse_id_7, c1_.car_id AS car_id_8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE c0_.discr IN (?)',
[],
[1 => $this->entityManager->getClassMetadata(CompanyEmployee::class)]
);
@@ -581,7 +575,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN (1, 2)',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE c0_.id IN (1, 2)'
'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_ WHERE c0_.id IN (1, 2)'
);
}
@@ -589,7 +583,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :id NOT IN (1)',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE ? NOT IN (1)'
'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_ WHERE ? NOT IN (1)'
);
}
@@ -606,7 +600,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u WHERE u.avatar IN (?1, ?2)',
'SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ WHERE f0_.avatar_id IN (?, ?)'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ WHERE f0_.avatar_id IN (?, ?)'
);
}
@@ -625,11 +619,11 @@ class SelectSqlGenerationTest extends OrmTestCase
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u WHERE u.username IN (FOO('Lo'), 'Lo', :name)",
"SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ WHERE f0_.username IN (ABS('Lo'), 'Lo', ?)"
"SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ WHERE f0_.username IN (ABS('Lo'), 'Lo', ?)"
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u WHERE u.id IN (1 + 1)',
'SELECT f0_.id AS id_0, f0_.username AS username_1 FROM forum_users f0_ WHERE f0_.id IN (1 + 1)'
'SELECT f0_.id AS id_0, f0_.username AS username_1, f0_.avatar_id AS avatar_id_2 FROM forum_users f0_ WHERE f0_.id IN (1 + 1)'
);
}
@@ -674,7 +668,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE (u.id >= (SELECT u2.id FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE u2.name = :name)) AND (u.id <= (SELECT u3.id FROM Doctrine\Tests\Models\CMS\CmsUser u3 WHERE u3.name = :name))',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE (c0_.id >= (SELECT c1_.id FROM cms_users c1_ WHERE c1_.name = ?)) AND (c0_.id <= (SELECT c2_.id FROM cms_users c2_ WHERE c2_.name = ?))'
'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_ WHERE (c0_.id >= (SELECT c1_.id FROM cms_users c1_ WHERE c1_.name = ?)) AND (c0_.id <= (SELECT c2_.id FROM cms_users c2_ WHERE c2_.name = ?))'
);
}
@@ -682,7 +676,6 @@ class SelectSqlGenerationTest extends OrmTestCase
{
// "Get all users who have $phone as a phonenumber." (*cough* doesnt really make sense...)
$q = $this->entityManager->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers');
$q->setHint(ORMQuery::HINT_FORCE_PARTIAL_LOAD, true);
$phone = new CmsPhonenumber();
$phone->phonenumber = 101;
@@ -698,7 +691,6 @@ class SelectSqlGenerationTest extends OrmTestCase
{
// "Get all users who are members of $group."
$q = $this->entityManager->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.groups');
$q->setHint(ORMQuery::HINT_FORCE_PARTIAL_LOAD, true);
$group = new CmsGroup();
$group->id = 101;
@@ -713,7 +705,6 @@ class SelectSqlGenerationTest extends OrmTestCase
public function testSupportsMemberOfExpressionManyToManyParameterArray(): void
{
$q = $this->entityManager->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.groups');
$q->setHint(ORMQuery::HINT_FORCE_PARTIAL_LOAD, true);
$group = new CmsGroup();
$group->id = 101;
@@ -766,21 +757,18 @@ class SelectSqlGenerationTest extends OrmTestCase
public function testSupportsCurrentDateFunction(): void
{
$q = $this->entityManager->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.datetime > current_date()');
$q->setHint(ORMQuery::HINT_FORCE_PARTIAL_LOAD, true);
self::assertEquals('SELECT d0_.id AS id_0 FROM date_time_model d0_ WHERE d0_.col_datetime > CURRENT_DATE', $q->getSql());
}
public function testSupportsCurrentTimeFunction(): void
{
$q = $this->entityManager->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.time > current_time()');
$q->setHint(ORMQuery::HINT_FORCE_PARTIAL_LOAD, true);
self::assertEquals('SELECT d0_.id AS id_0 FROM date_time_model d0_ WHERE d0_.col_time > CURRENT_TIME', $q->getSql());
}
public function testSupportsCurrentTimestampFunction(): void
{
$q = $this->entityManager->createQuery('SELECT d.id FROM Doctrine\Tests\Models\Generic\DateTimeModel d WHERE d.datetime > current_timestamp()');
$q->setHint(ORMQuery::HINT_FORCE_PARTIAL_LOAD, true);
self::assertEquals('SELECT d0_.id AS id_0 FROM date_time_model d0_ WHERE d0_.col_datetime > CURRENT_TIMESTAMP', $q->getSql());
}
@@ -795,10 +783,7 @@ class SelectSqlGenerationTest extends OrmTestCase
FROM Doctrine\Tests\Models\CMS\CmsEmployee spouseEmp
WHERE spouseEmp = emp.spouse)',
// SQL
'SELECT DISTINCT c0_.id AS id_0, c0_.name AS name_1 FROM cms_employees c0_'
. ' WHERE EXISTS ('
. 'SELECT c1_.id FROM cms_employees c1_ WHERE c1_.id = c0_.spouse_id'
. ')'
'SELECT DISTINCT c0_.id AS id_0, c0_.name AS name_1, c0_.spouse_id AS spouse_id_2 FROM cms_employees c0_ WHERE EXISTS (SELECT c1_.id FROM cms_employees c1_ WHERE c1_.id = c0_.spouse_id)'
);
}
@@ -813,10 +798,7 @@ class SelectSqlGenerationTest extends OrmTestCase
FROM Doctrine\Tests\Models\CMS\CmsEmployee spouseEmp
WHERE spouseEmp = emp.spouse)',
// SQL
'SELECT DISTINCT c0_.id AS id_0, c0_.name AS name_1 FROM cms_employees c0_'
. ' WHERE EXISTS ('
. 'SELECT 1 AS sclr_2 FROM cms_employees c1_ WHERE c1_.id = c0_.spouse_id'
. ')'
'SELECT DISTINCT c0_.id AS id_0, c0_.name AS name_1, c0_.spouse_id AS spouse_id_2 FROM cms_employees c0_ WHERE EXISTS (SELECT 1 AS sclr_3 FROM cms_employees c1_ WHERE c1_.id = c0_.spouse_id)'
);
}
@@ -850,7 +832,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE SIZE(u.phonenumbers) > 1',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE (SELECT COUNT(*) FROM cms_phonenumbers c1_ WHERE c1_.user_id = c0_.id) > 1'
'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_ WHERE (SELECT COUNT(*) FROM cms_phonenumbers c1_ WHERE c1_.user_id = c0_.id) > 1'
);
}
@@ -858,7 +840,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE SIZE(u.groups) > 1',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE (SELECT COUNT(*) FROM cms_users_groups c1_ WHERE c1_.user_id = c0_.id) > 1'
'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_ WHERE (SELECT COUNT(*) FROM cms_users_groups c1_ WHERE c1_.user_id = c0_.id) > 1'
);
}
@@ -866,11 +848,11 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.phonenumbers IS EMPTY',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE (SELECT COUNT(*) FROM cms_phonenumbers c1_ WHERE c1_.user_id = c0_.id) = 0'
'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_ WHERE (SELECT COUNT(*) FROM cms_phonenumbers c1_ WHERE c1_.user_id = c0_.id) = 0'
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.phonenumbers IS NOT EMPTY',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE (SELECT COUNT(*) FROM cms_phonenumbers c1_ WHERE c1_.user_id = c0_.id) > 0'
'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_ WHERE (SELECT COUNT(*) FROM cms_phonenumbers c1_ WHERE c1_.user_id = c0_.id) > 0'
);
}
@@ -878,7 +860,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'select u from Doctrine\Tests\Models\CMS\CmsUser u where u.id > 10 and u.id < 42 and ((u.id * 2) > 5)',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE c0_.id > 10 AND c0_.id < 42 AND ((c0_.id * 2) > 5)'
'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_ WHERE c0_.id > 10 AND c0_.id < 42 AND ((c0_.id * 2) > 5)'
);
}
@@ -886,7 +868,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'select u from Doctrine\Tests\Models\CMS\CmsUser u where (u.id > 10) and (u.id < 42 and ((u.id * 2) > 5)) or u.id <> 42',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE (c0_.id > 10) AND (c0_.id < 42 AND ((c0_.id * 2) > 5)) OR c0_.id <> 42'
'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_ WHERE (c0_.id > 10) AND (c0_.id < 42 AND ((c0_.id * 2) > 5)) OR c0_.id <> 42'
);
}
@@ -894,7 +876,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'select u from Doctrine\Tests\Models\CMS\CmsUser u where (u.id > 10) and (u.id between 1 and 10 or u.id in (1, 2, 3, 4, 5))',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE (c0_.id > 10) AND (c0_.id BETWEEN 1 AND 10 OR c0_.id IN (1, 2, 3, 4, 5))'
'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_ WHERE (c0_.id > 10) AND (c0_.id BETWEEN 1 AND 10 OR c0_.id IN (1, 2, 3, 4, 5))'
);
}
@@ -902,7 +884,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'select u, size(u.articles) as numArticles from Doctrine\Tests\Models\CMS\CmsUser u order by numArticles',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, (SELECT COUNT(*) FROM cms_articles c1_ WHERE c1_.user_id = c0_.id) AS sclr_4 FROM cms_users c0_ ORDER BY sclr_4 ASC'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, (SELECT COUNT(*) FROM cms_articles c1_ WHERE c1_.user_id = c0_.id) AS sclr_4, c0_.email_id AS email_id_5 FROM cms_users c0_ ORDER BY sclr_4 ASC'
);
}
@@ -910,7 +892,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'select a from Doctrine\Tests\Models\CMS\CmsArticle a order by a.user',
'SELECT c0_.id AS id_0, c0_.topic AS topic_1, c0_.text AS text_2, c0_.version AS version_3 FROM cms_articles c0_ ORDER BY c0_.user_id ASC'
'SELECT c0_.id AS id_0, c0_.topic AS topic_1, c0_.text AS text_2, c0_.version AS version_3, c0_.user_id AS user_id_4 FROM cms_articles c0_ ORDER BY c0_.user_id ASC'
);
}
@@ -961,7 +943,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user = ?1',
'SELECT c0_.phonenumber AS phonenumber_0 FROM cms_phonenumbers c0_ WHERE c0_.user_id = ?'
'SELECT c0_.phonenumber AS phonenumber_0, c0_.user_id AS user_id_1 FROM cms_phonenumbers c0_ WHERE c0_.user_id = ?'
);
}
@@ -969,7 +951,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT a FROM Doctrine\Tests\Models\CMS\CmsAddress a WHERE a.user IS NULL',
'SELECT c0_.id AS id_0, c0_.country AS country_1, c0_.zip AS zip_2, c0_.city AS city_3 FROM cms_addresses c0_ WHERE c0_.user_id IS NULL'
'SELECT c0_.id AS id_0, c0_.country AS country_1, c0_.zip AS zip_2, c0_.city AS city_3, c0_.user_id AS user_id_4 FROM cms_addresses c0_ WHERE c0_.user_id IS NULL'
);
}
@@ -982,7 +964,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.address a WHERE a.id IS NULL',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ LEFT JOIN cms_addresses c1_ ON c0_.id = c1_.user_id WHERE c1_.id IS NULL'
'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_ LEFT JOIN cms_addresses c1_ ON c0_.id = c1_.user_id WHERE c1_.id IS NULL'
);
}
@@ -1016,7 +998,7 @@ class SelectSqlGenerationTest extends OrmTestCase
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a WITH a.topic LIKE u.name',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic LIKE c0_.name)'
'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_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic LIKE c0_.name)'
);
}
@@ -1034,7 +1016,7 @@ class SelectSqlGenerationTest extends OrmTestCase
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a WITH a.topic NOT LIKE u.name',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic NOT LIKE c0_.name)'
'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_ LEFT JOIN cms_articles c1_ ON c0_.id = c1_.user_id AND (c1_.topic NOT LIKE c0_.name)'
);
}
@@ -1043,8 +1025,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT r, l FROM Doctrine\Tests\Models\Routing\RoutingRoute r JOIN r.legs l',
'SELECT r0_.id AS id_0, r1_.id AS id_1, r1_.departureDate AS departureDate_2, r1_.arrivalDate AS arrivalDate_3 FROM RoutingRoute r0_ INNER JOIN RoutingRouteLegs r2_ ON r0_.id = r2_.route_id INNER JOIN RoutingLeg r1_ ON r1_.id = r2_.leg_id ' .
'ORDER BY r1_.departureDate ASC'
'SELECT r0_.id AS id_0, r1_.id AS id_1, r1_.departureDate AS departureDate_2, r1_.arrivalDate AS arrivalDate_3, r1_.from_id AS from_id_4, r1_.to_id AS to_id_5 FROM RoutingRoute r0_ INNER JOIN RoutingRouteLegs r2_ ON r0_.id = r2_.route_id INNER JOIN RoutingLeg r1_ ON r1_.id = r2_.leg_id ORDER BY r1_.departureDate ASC'
);
}
@@ -1068,8 +1049,7 @@ class SelectSqlGenerationTest extends OrmTestCase
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'",
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 ' .
"FROM cms_users c0_ WHERE c0_.username = 'gblanco' FOR UPDATE",
"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_ WHERE c0_.username = 'gblanco' FOR UPDATE",
[ORMQuery::HINT_LOCK_MODE => LockMode::PESSIMISTIC_WRITE]
);
}
@@ -1084,8 +1064,7 @@ class SelectSqlGenerationTest extends OrmTestCase
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'",
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 ' .
"FROM cms_users c0_ WHERE c0_.username = 'gblanco' FOR SHARE",
"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_ WHERE c0_.username = 'gblanco' FOR SHARE",
[ORMQuery::HINT_LOCK_MODE => LockMode::PESSIMISTIC_READ]
);
}
@@ -1098,8 +1077,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'",
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 ' .
"FROM cms_users c0_ WHERE c0_.username = 'gblanco'",
"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_ WHERE c0_.username = 'gblanco'",
[ORMQuery::HINT_LOCK_MODE => LockMode::NONE]
);
}
@@ -1109,7 +1087,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1 OR u.id = ?2 OR u.id = ?3 OR u.id = ?4 OR u.id = ?5 OR u.id = ?6 OR u.id = ?7 OR u.id = ?8 OR u.id = ?9 OR u.id = ?10 OR u.id = ?11',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ?'
'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_ WHERE c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ? OR c0_.id = ?'
);
}
@@ -1123,8 +1101,7 @@ class SelectSqlGenerationTest extends OrmTestCase
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'",
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 ' .
"FROM cms_users c0_ WHERE c0_.username = 'gblanco' LOCK IN SHARE MODE",
"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_ WHERE c0_.username = 'gblanco' LOCK IN SHARE MODE",
[ORMQuery::HINT_LOCK_MODE => LockMode::PESSIMISTIC_READ]
);
}
@@ -1139,8 +1116,7 @@ class SelectSqlGenerationTest extends OrmTestCase
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username = 'gblanco'",
'SELECT c0_.id AS ID_0, c0_.status AS STATUS_1, c0_.username AS USERNAME_2, c0_.name AS NAME_3 ' .
"FROM cms_users c0_ WHERE c0_.username = 'gblanco' FOR UPDATE",
"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_ WHERE c0_.username = 'gblanco' FOR UPDATE",
[ORMQuery::HINT_LOCK_MODE => LockMode::PESSIMISTIC_READ]
);
}
@@ -1164,7 +1140,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT f FROM Doctrine\Tests\Models\DirectoryTree\File f JOIN f.parentDirectory d WHERE f.id = ?1',
'SELECT f0_.id AS id_0, f0_.extension AS extension_1, f0_.name AS name_2 FROM "file" f0_ INNER JOIN Directory d1_ ON f0_.parentDirectory_id = d1_.id WHERE f0_.id = ?'
'SELECT f0_.id AS id_0, f0_.extension AS extension_1, f0_.name AS name_2, f0_.parentDirectory_id AS parentDirectory_id_3 FROM "file" f0_ INNER JOIN Directory d1_ ON f0_.parentDirectory_id = d1_.id WHERE f0_.id = ?'
);
}
@@ -1232,7 +1208,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT uo, (SELECT ui.name FROM Doctrine\Tests\Models\CMS\CmsUser ui WHERE ui.id = uo.id) AS bar FROM Doctrine\Tests\Models\CMS\CmsUser uo',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, (SELECT c1_.name FROM cms_users c1_ WHERE c1_.id = c0_.id) AS sclr_4 FROM cms_users c0_'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, (SELECT c1_.name FROM cms_users c1_ WHERE c1_.id = c0_.id) AS sclr_4, c0_.email_id AS email_id_5 FROM cms_users c0_'
);
}
@@ -1240,7 +1216,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT uo, (SELECT ui.name FROM Doctrine\Tests\Models\CMS\CmsUser ui WHERE ui.id = uo.id AND ui.name IN (SELECT uii.name FROM Doctrine\Tests\Models\CMS\CmsUser uii)) AS bar FROM Doctrine\Tests\Models\CMS\CmsUser uo',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, (SELECT c1_.name FROM cms_users c1_ WHERE c1_.id = c0_.id AND c1_.name IN (SELECT c2_.name FROM cms_users c2_)) AS sclr_4 FROM cms_users c0_'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, (SELECT c1_.name FROM cms_users c1_ WHERE c1_.id = c0_.id AND c1_.name IN (SELECT c2_.name FROM cms_users c2_)) AS sclr_4, c0_.email_id AS email_id_5 FROM cms_users c0_'
);
}
@@ -1248,7 +1224,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT uo, (SELECT ui.name FROM Doctrine\Tests\Models\CMS\CmsUser ui WHERE ui.id = uo.id) AS bar FROM Doctrine\Tests\Models\CMS\CmsUser uo WHERE bar = ?0',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, (SELECT c1_.name FROM cms_users c1_ WHERE c1_.id = c0_.id) AS sclr_4 FROM cms_users c0_ WHERE sclr_4 = ?'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, (SELECT c1_.name FROM cms_users c1_ WHERE c1_.id = c0_.id) AS sclr_4, c0_.email_id AS email_id_5 FROM cms_users c0_ WHERE sclr_4 = ?'
);
}
@@ -1414,13 +1390,13 @@ class SelectSqlGenerationTest extends OrmTestCase
//relation is in the subclass (CompanyManager) we are querying
$this->assertSqlGeneration(
'SELECT m, IDENTITY(m.car) as car_id FROM Doctrine\Tests\Models\Company\CompanyManager m',
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c2_.title AS title_5, c2_.car_id AS sclr_6, c0_.discr AS discr_7 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id'
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c2_.title AS title_5, c2_.car_id AS sclr_6, c0_.discr AS discr_7, c0_.spouse_id AS spouse_id_8, c2_.car_id AS car_id_9 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id'
);
//relation is in the base class (CompanyPerson).
$this->assertSqlGeneration(
'SELECT m, IDENTITY(m.spouse) as spouse_id FROM Doctrine\Tests\Models\Company\CompanyManager m',
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c2_.title AS title_5, c0_.spouse_id AS sclr_6, c0_.discr AS discr_7 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id'
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c2_.title AS title_5, c0_.spouse_id AS sclr_6, c0_.discr AS discr_7, c0_.spouse_id AS spouse_id_8, c2_.car_id AS car_id_9 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id'
);
}
@@ -1558,8 +1534,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT p, pp FROM Doctrine\Tests\Models\Company\CompanyPerson p JOIN p.spouse pp',
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.title AS title_2, c2_.salary AS salary_3, c2_.department AS department_4, c2_.startDate AS startDate_5, c3_.id AS id_6, c3_.name AS name_7, c4_.title AS title_8, c5_.salary AS salary_9, c5_.department AS department_10, c5_.startDate AS startDate_11, c0_.discr AS discr_12, c0_.spouse_id AS spouse_id_13, c1_.car_id AS car_id_14, c3_.discr AS discr_15, c3_.spouse_id AS spouse_id_16, c4_.car_id AS car_id_17 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ ON c0_.spouse_id = c3_.id LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id',
[ORMQuery::HINT_FORCE_PARTIAL_LOAD => false]
'SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.title AS title_2, c2_.salary AS salary_3, c2_.department AS department_4, c2_.startDate AS startDate_5, c3_.id AS id_6, c3_.name AS name_7, c4_.title AS title_8, c5_.salary AS salary_9, c5_.department AS department_10, c5_.startDate AS startDate_11, c0_.discr AS discr_12, c0_.spouse_id AS spouse_id_13, c1_.car_id AS car_id_14, c3_.discr AS discr_15, c3_.spouse_id AS spouse_id_16, c4_.car_id AS car_id_17 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ ON c0_.spouse_id = c3_.id LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id'
);
}
@@ -1580,7 +1555,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT e.name FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
'SELECT c0_.name AS name_0 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id'
'SELECT c0_.name AS name_0 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id'
);
}
@@ -1612,12 +1587,12 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY u',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ GROUP BY c0_.id, c0_.status, c0_.username, c0_.name, c0_.email_id'
'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_ GROUP BY c0_.id, c0_.status, c0_.username, c0_.name, c0_.email_id'
);
$this->assertSqlGeneration(
'SELECT e FROM Doctrine\Tests\Models\CMS\CmsEmployee e GROUP BY e',
'SELECT c0_.id AS id_0, c0_.name AS name_1 FROM cms_employees c0_ GROUP BY c0_.id, c0_.name, c0_.spouse_id'
'SELECT c0_.id AS id_0, c0_.name AS name_1, c0_.spouse_id AS spouse_id_2 FROM cms_employees c0_ GROUP BY c0_.id, c0_.name, c0_.spouse_id'
);
}
@@ -1626,7 +1601,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u, u.status AS st FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY st',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c0_.status AS status_4 FROM cms_users c0_ GROUP BY c0_.status'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, c0_.status AS status_4, c0_.email_id AS email_id_5 FROM cms_users c0_ GROUP BY c0_.status'
);
}
@@ -1635,7 +1610,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u AS user FROM Doctrine\Tests\Models\CMS\CmsUser u GROUP BY user',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ GROUP BY id_0, status_1, username_2, name_3'
'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_ GROUP BY id_0, status_1, username_2, name_3'
);
}
@@ -1644,7 +1619,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT BIT_OR(4,2), BIT_AND(4,2), u FROM Doctrine\Tests\Models\CMS\CmsUser u',
'SELECT (4 | 2) AS sclr_0, (4 & 2) AS sclr_1, c0_.id AS id_2, c0_.status AS status_3, c0_.username AS username_4, c0_.name AS name_5 FROM cms_users c0_'
'SELECT (4 | 2) AS sclr_0, (4 & 2) AS sclr_1, c0_.id AS id_2, c0_.status AS status_3, c0_.username AS username_4, c0_.name AS name_5, c0_.email_id AS email_id_6 FROM cms_users c0_'
);
$this->assertSqlGeneration(
'SELECT BIT_OR(u.id,2), BIT_AND(u.id,2) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE BIT_OR(u.id,2) > 0',
@@ -1665,15 +1640,15 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u where ( (u.id + u.id) * u.id ) > 100',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE ((c0_.id + c0_.id) * c0_.id) > 100'
'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_ WHERE ((c0_.id + c0_.id) * c0_.id) > 100'
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u where (u.id + u.id) * u.id > 100',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE (c0_.id + c0_.id) * c0_.id > 100'
'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_ WHERE (c0_.id + c0_.id) * c0_.id > 100'
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u where 100 < (u.id + u.id) * u.id ',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE 100 < (c0_.id + c0_.id) * c0_.id'
'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_ WHERE 100 < (c0_.id + c0_.id) * c0_.id'
);
}
@@ -1690,27 +1665,27 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.name IN ( SELECT TRIM(u2.name) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE c0_.name IN (SELECT TRIM(c1_.name) AS sclr_4 FROM cms_users c1_)'
'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_ WHERE c0_.name IN (SELECT TRIM(c1_.name) AS sclr_5 FROM cms_users c1_)'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.name IN ( SELECT TRIM(u2.name) FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE LOWER(u2.name) LIKE \'%fabio%\')',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE c0_.name IN (SELECT TRIM(c1_.name) AS sclr_4 FROM cms_users c1_ WHERE LOWER(c1_.name) LIKE \'%fabio%\')'
'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_ WHERE c0_.name IN (SELECT TRIM(c1_.name) AS sclr_5 FROM cms_users c1_ WHERE LOWER(c1_.name) LIKE \'%fabio%\')'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.email IN ( SELECT TRIM(IDENTITY(u2.email)) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE c0_.email_id IN (SELECT TRIM(c1_.email_id) AS sclr_4 FROM cms_users c1_)'
'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_ WHERE c0_.email_id IN (SELECT TRIM(c1_.email_id) AS sclr_5 FROM cms_users c1_)'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE u1.email IN ( SELECT IDENTITY(u2.email) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE c0_.email_id IN (SELECT c1_.email_id AS sclr_4 FROM cms_users c1_)'
'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_ WHERE c0_.email_id IN (SELECT c1_.email_id AS sclr_5 FROM cms_users c1_)'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE COUNT(u1.id) = ( SELECT SUM(u2.id) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE COUNT(c0_.id) = (SELECT SUM(c1_.id) AS sclr_4 FROM cms_users c1_)'
'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_ WHERE COUNT(c0_.id) = (SELECT SUM(c1_.id) AS sclr_5 FROM cms_users c1_)'
);
$this->assertSqlGeneration(
'SELECT u1 FROM Doctrine\Tests\Models\CMS\CmsUser u1 WHERE COUNT(u1.id) <= ( SELECT SUM(u2.id) + COUNT(u2.email) FROM Doctrine\Tests\Models\CMS\CmsUser u2 )',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE COUNT(c0_.id) <= (SELECT SUM(c1_.id) + COUNT(c1_.email_id) AS sclr_4 FROM cms_users c1_)'
'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_ WHERE COUNT(c0_.id) <= (SELECT SUM(c1_.id) + COUNT(c1_.email_id) AS sclr_5 FROM cms_users c1_)'
);
}
@@ -1753,37 +1728,37 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE IDENTITY(u.email) IS NULL',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE c0_.email_id IS NULL'
'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_ WHERE c0_.email_id IS NULL'
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE NULLIF(u.name, 'FabioBatSilva') IS NULL AND IDENTITY(u.email) IS NOT NULL",
"SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE NULLIF(c0_.name, 'FabioBatSilva') IS NULL AND c0_.email_id IS NOT NULL"
"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_ WHERE NULLIF(c0_.name, 'FabioBatSilva') IS NULL AND c0_.email_id IS NOT NULL"
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE IDENTITY(u.email) IS NOT NULL',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE c0_.email_id IS NOT NULL'
'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_ WHERE c0_.email_id IS NOT NULL'
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE NULLIF(u.name, 'FabioBatSilva') IS NOT NULL",
"SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE NULLIF(c0_.name, 'FabioBatSilva') IS NOT NULL"
"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_ WHERE NULLIF(c0_.name, 'FabioBatSilva') IS NOT NULL"
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE COALESCE(u.name, u.id) IS NOT NULL',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE COALESCE(c0_.name, c0_.id) IS NOT NULL'
'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_ WHERE COALESCE(c0_.name, c0_.id) IS NOT NULL'
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE COALESCE(u.id, IDENTITY(u.email)) IS NOT NULL',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE COALESCE(c0_.id, c0_.email_id) IS NOT NULL'
'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_ WHERE COALESCE(c0_.id, c0_.email_id) IS NOT NULL'
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE COALESCE(IDENTITY(u.email), NULLIF(u.name, 'FabioBatSilva')) IS NOT NULL",
"SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ WHERE COALESCE(c0_.email_id, NULLIF(c0_.name, 'FabioBatSilva')) IS NOT NULL"
"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_ WHERE COALESCE(c0_.email_id, NULLIF(c0_.name, 'FabioBatSilva')) IS NOT NULL"
);
}
@@ -1825,7 +1800,7 @@ class SelectSqlGenerationTest extends OrmTestCase
$this->assertSqlGeneration(
'SELECT p FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p',
'SELECT c0_.id AS id_0, -(c0_.customInteger) AS customInteger_1 FROM customtype_parents c0_'
'SELECT c0_.id AS id_0, -(c0_.customInteger) AS customInteger_1, c0_.child_id AS child_id_2 FROM customtype_parents c0_'
);
}
@@ -1839,7 +1814,7 @@ class SelectSqlGenerationTest extends OrmTestCase
$this->assertSqlGeneration(
'SELECT partial p.{id, customInteger} FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p',
'SELECT c0_.id AS id_0, -(c0_.customInteger) AS customInteger_1 FROM customtype_parents c0_'
'SELECT c0_.id AS id_0, -(c0_.customInteger) AS customInteger_1, c0_.child_id AS child_id_2 FROM customtype_parents c0_'
);
}
@@ -1848,7 +1823,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT fix, flex FROM Doctrine\Tests\Models\Company\CompanyFixContract fix, Doctrine\Tests\Models\Company\CompanyFlexContract flex',
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c1_.id AS id_3, c1_.completed AS completed_4, c1_.hoursWorked AS hoursWorked_5, c1_.pricePerHour AS pricePerHour_6, c1_.maxPrice AS maxPrice_7, c0_.discr AS discr_8, c1_.discr AS discr_9 FROM company_contracts c0_, company_contracts c1_ WHERE (c0_.discr IN ('fix') AND c1_.discr IN ('flexible', 'flexultra'))"
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c1_.id AS id_3, c1_.completed AS completed_4, c1_.hoursWorked AS hoursWorked_5, c1_.pricePerHour AS pricePerHour_6, c1_.maxPrice AS maxPrice_7, c0_.discr AS discr_8, c0_.salesPerson_id AS salesPerson_id_9, c1_.discr AS discr_10, c1_.salesPerson_id AS salesPerson_id_11 FROM company_contracts c0_, company_contracts c1_ WHERE (c0_.discr IN ('fix') AND c1_.discr IN ('flexible', 'flexultra'))"
);
}
@@ -1857,15 +1832,15 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.id + 1 ',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ ORDER BY c0_.id + 1 ASC'
'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_ ORDER BY c0_.id + 1 ASC'
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY ( ( (u.id + 1) * (u.id - 1) ) / 2)',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ ORDER BY (((c0_.id + 1) * (c0_.id - 1)) / 2) ASC'
'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_ ORDER BY (((c0_.id + 1) * (c0_.id - 1)) / 2) ASC'
);
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY ((u.id + 5000) * u.id + 3) ',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ ORDER BY ((c0_.id + 5000) * c0_.id + 3) ASC'
'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_ ORDER BY ((c0_.id + 5000) * c0_.id + 3) ASC'
);
}
@@ -1873,7 +1848,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY CONCAT(u.username, u.name) ',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3 FROM cms_users c0_ ORDER BY c0_.username || c0_.name ASC'
'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_ ORDER BY c0_.username || c0_.name ASC'
);
}
@@ -1929,32 +1904,34 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u, a FROM Doctrine\Tests\Models\Quote\User u JOIN u.address a',
'SELECT q0_."user-id" AS userid_0, q0_."user-name" AS username_1, q1_."address-id" AS addressid_2, q1_."address-zip" AS addresszip_3, q1_.type AS type_4 FROM "quote-user" q0_ INNER JOIN "quote-address" q1_ ON q0_."user-id" = q1_."user-id" AND q1_.type IN (\'simple\', \'full\')'
<<<'SQL'
SELECT q0_."user-id" AS userid_0, q0_."user-name" AS username_1, q1_."address-id" AS addressid_2, q1_."address-zip" AS addresszip_3, q1_.type AS type_4, q1_."user-id" AS userid_5, q1_."city-id" AS cityid_6 FROM "quote-user" q0_ INNER JOIN "quote-address" q1_ ON q0_."user-id" = q1_."user-id" AND q1_.type IN ('simple', 'full')
SQL
);
$this->assertSqlGeneration(
'SELECT u, p FROM Doctrine\Tests\Models\Quote\User u JOIN u.phones p',
'SELECT q0_."user-id" AS userid_0, q0_."user-name" AS username_1, q1_."phone-number" AS phonenumber_2 FROM "quote-user" q0_ INNER JOIN "quote-phone" q1_ ON q0_."user-id" = q1_."user-id"'
'SELECT q0_."user-id" AS userid_0, q0_."user-name" AS username_1, q1_."phone-number" AS phonenumber_2, q1_."user-id" AS userid_3 FROM "quote-user" q0_ INNER JOIN "quote-phone" q1_ ON q0_."user-id" = q1_."user-id"'
);
$this->assertSqlGeneration(
'SELECT u, g FROM Doctrine\Tests\Models\Quote\User u JOIN u.groups g',
'SELECT q0_."user-id" AS userid_0, q0_."user-name" AS username_1, q1_."group-id" AS groupid_2, q1_."group-name" AS groupname_3 FROM "quote-user" q0_ INNER JOIN "quote-users-groups" q2_ ON q0_."user-id" = q2_."user-id" INNER JOIN "quote-group" q1_ ON q1_."group-id" = q2_."group-id"'
'SELECT q0_."user-id" AS userid_0, q0_."user-name" AS username_1, q1_."group-id" AS groupid_2, q1_."group-name" AS groupname_3, q1_."parent-id" AS parentid_4 FROM "quote-user" q0_ INNER JOIN "quote-users-groups" q2_ ON q0_."user-id" = q2_."user-id" INNER JOIN "quote-group" q1_ ON q1_."group-id" = q2_."group-id"'
);
$this->assertSqlGeneration(
'SELECT a, u FROM Doctrine\Tests\Models\Quote\Address a JOIN a.user u',
'SELECT q0_."address-id" AS addressid_0, q0_."address-zip" AS addresszip_1, q1_."user-id" AS userid_2, q1_."user-name" AS username_3, q0_.type AS type_4 FROM "quote-address" q0_ INNER JOIN "quote-user" q1_ ON q0_."user-id" = q1_."user-id" WHERE q0_.type IN (\'simple\', \'full\')'
'SELECT q0_."address-id" AS addressid_0, q0_."address-zip" AS addresszip_1, q1_."user-id" AS userid_2, q1_."user-name" AS username_3, q0_.type AS type_4, q0_."user-id" AS userid_5, q0_."city-id" AS cityid_6 FROM "quote-address" q0_ INNER JOIN "quote-user" q1_ ON q0_."user-id" = q1_."user-id" WHERE q0_.type IN (\'simple\', \'full\')'
);
$this->assertSqlGeneration(
'SELECT g, u FROM Doctrine\Tests\Models\Quote\Group g JOIN g.users u',
'SELECT q0_."group-id" AS groupid_0, q0_."group-name" AS groupname_1, q1_."user-id" AS userid_2, q1_."user-name" AS username_3 FROM "quote-group" q0_ INNER JOIN "quote-users-groups" q2_ ON q0_."group-id" = q2_."group-id" INNER JOIN "quote-user" q1_ ON q1_."user-id" = q2_."user-id"'
'SELECT q0_."group-id" AS groupid_0, q0_."group-name" AS groupname_1, q1_."user-id" AS userid_2, q1_."user-name" AS username_3, q0_."parent-id" AS parentid_4 FROM "quote-group" q0_ INNER JOIN "quote-users-groups" q2_ ON q0_."group-id" = q2_."group-id" INNER JOIN "quote-user" q1_ ON q1_."user-id" = q2_."user-id"'
);
$this->assertSqlGeneration(
'SELECT g, p FROM Doctrine\Tests\Models\Quote\Group g JOIN g.parent p',
'SELECT q0_."group-id" AS groupid_0, q0_."group-name" AS groupname_1, q1_."group-id" AS groupid_2, q1_."group-name" AS groupname_3 FROM "quote-group" q0_ INNER JOIN "quote-group" q1_ ON q0_."parent-id" = q1_."group-id"'
'SELECT q0_."group-id" AS groupid_0, q0_."group-name" AS groupname_1, q1_."group-id" AS groupid_2, q1_."group-name" AS groupname_3, q0_."parent-id" AS parentid_4, q1_."parent-id" AS parentid_5 FROM "quote-group" q0_ INNER JOIN "quote-group" q1_ ON q0_."parent-id" = q1_."group-id"'
);
}
@@ -1963,17 +1940,17 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT SUM(CASE WHEN e.salary <= :value THEN e.salary - :value WHEN e.salary >= :value THEN :value - e.salary ELSE 0 END) FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
'SELECT SUM(CASE WHEN c0_.salary <= ? THEN c0_.salary - ? WHEN c0_.salary >= ? THEN ? - c0_.salary ELSE 0 END) AS sclr_0 FROM company_employees c0_ INNER JOIN company_persons c1_ ON c0_.id = c1_.id'
'SELECT SUM(CASE WHEN c0_.salary <= ? THEN c0_.salary - ? WHEN c0_.salary >= ? THEN ? - c0_.salary ELSE 0 END) AS sclr_0 FROM company_employees c0_ INNER JOIN company_persons c1_ ON c0_.id = c1_.id LEFT JOIN company_managers c2_ ON c0_.id = c2_.id'
);
$this->assertSqlGeneration(
'SELECT SUM(CASE WHEN e.salary <= :value THEN e.salary - :value WHEN e.salary >= :value THEN :value - e.salary ELSE e.salary + 0 END) FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
'SELECT SUM(CASE WHEN c0_.salary <= ? THEN c0_.salary - ? WHEN c0_.salary >= ? THEN ? - c0_.salary ELSE c0_.salary + 0 END) AS sclr_0 FROM company_employees c0_ INNER JOIN company_persons c1_ ON c0_.id = c1_.id'
'SELECT SUM(CASE WHEN c0_.salary <= ? THEN c0_.salary - ? WHEN c0_.salary >= ? THEN ? - c0_.salary ELSE c0_.salary + 0 END) AS sclr_0 FROM company_employees c0_ INNER JOIN company_persons c1_ ON c0_.id = c1_.id LEFT JOIN company_managers c2_ ON c0_.id = c2_.id'
);
$this->assertSqlGeneration(
'SELECT SUM(CASE WHEN e.salary <= :value THEN (e.salary - :value) WHEN e.salary >= :value THEN (:value - e.salary) ELSE (e.salary + :value) END) FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
'SELECT SUM(CASE WHEN c0_.salary <= ? THEN (c0_.salary - ?) WHEN c0_.salary >= ? THEN (? - c0_.salary) ELSE (c0_.salary + ?) END) AS sclr_0 FROM company_employees c0_ INNER JOIN company_persons c1_ ON c0_.id = c1_.id'
'SELECT SUM(CASE WHEN c0_.salary <= ? THEN (c0_.salary - ?) WHEN c0_.salary >= ? THEN (? - c0_.salary) ELSE (c0_.salary + ?) END) AS sclr_0 FROM company_employees c0_ INNER JOIN company_persons c1_ ON c0_.id = c1_.id LEFT JOIN company_managers c2_ ON c0_.id = c2_.id'
);
}
@@ -2039,12 +2016,12 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT r, b FROM Doctrine\Tests\Models\Routing\RoutingRoute r JOIN r.bookings b',
'SELECT r0_.id AS id_0, r1_.id AS id_1, r1_.passengerName AS passengerName_2 FROM RoutingRoute r0_ INNER JOIN RoutingRouteBooking r1_ ON r0_.id = r1_.route_id ORDER BY r1_.passengerName ASC'
'SELECT r0_.id AS id_0, r1_.id AS id_1, r1_.passengerName AS passengerName_2, r1_.route_id AS route_id_3 FROM RoutingRoute r0_ INNER JOIN RoutingRouteBooking r1_ ON r0_.id = r1_.route_id ORDER BY r1_.passengerName ASC'
);
$this->assertSqlGeneration(
'SELECT r, b FROM Doctrine\Tests\Models\Routing\RoutingRoute r JOIN r.bookings b ORDER BY b.passengerName DESC',
'SELECT r0_.id AS id_0, r1_.id AS id_1, r1_.passengerName AS passengerName_2 FROM RoutingRoute r0_ INNER JOIN RoutingRouteBooking r1_ ON r0_.id = r1_.route_id ORDER BY r1_.passengerName DESC'
'SELECT r0_.id AS id_0, r1_.id AS id_1, r1_.passengerName AS passengerName_2, r1_.route_id AS route_id_3 FROM RoutingRoute r0_ INNER JOIN RoutingRouteBooking r1_ ON r0_.id = r1_.route_id ORDER BY r1_.passengerName DESC'
);
}
@@ -2067,8 +2044,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT e.id FROM Doctrine\Tests\Models\Company\CompanyOrganization o JOIN o.events e WITH e.id = ?1',
'SELECT c0_.id AS id_0 FROM company_organizations c1_ INNER JOIN (company_events c0_ LEFT JOIN company_auctions c2_ ON c0_.id = c2_.id LEFT JOIN company_raffles c3_ ON c0_.id = c3_.id) ON c1_.id = c0_.org_id AND (c0_.id = ?)',
[ORMQuery::HINT_FORCE_PARTIAL_LOAD => false]
'SELECT c0_.id AS id_0 FROM company_organizations c1_ INNER JOIN (company_events c0_ LEFT JOIN company_auctions c2_ ON c0_.id = c2_.id LEFT JOIN company_raffles c3_ ON c0_.id = c3_.id) ON c1_.id = c0_.org_id AND (c0_.id = ?)'
);
}
@@ -2078,7 +2054,7 @@ class SelectSqlGenerationTest extends OrmTestCase
// Regression test for the bug
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyContract c WITH c.salesPerson = e.id',
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6, c0_.salesPerson_id AS salesPerson_id_7 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_managers c3_ ON c1_.id = c3_.id LEFT JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
);
}
@@ -2088,7 +2064,7 @@ class SelectSqlGenerationTest extends OrmTestCase
// Ensure other WHERE predicates are passed through to the main WHERE clause
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyEmployee e LEFT JOIN Doctrine\Tests\Models\Company\CompanyContract c WITH c.salesPerson = e.id WHERE e.salary > 1000',
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra') WHERE c1_.salary > 1000"
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6, c0_.salesPerson_id AS salesPerson_id_7 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_managers c3_ ON c1_.id = c3_.id LEFT JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra') WHERE c1_.salary > 1000"
);
}
@@ -2098,7 +2074,7 @@ class SelectSqlGenerationTest extends OrmTestCase
// Test inner joins too
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyEmployee e INNER JOIN Doctrine\Tests\Models\Company\CompanyContract c WITH c.salesPerson = e.id',
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id INNER JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6, c0_.salesPerson_id AS salesPerson_id_7 FROM company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_managers c3_ ON c1_.id = c3_.id INNER JOIN company_contracts c0_ ON (c0_.salesPerson_id = c2_.id) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
);
}
@@ -2109,7 +2085,7 @@ class SelectSqlGenerationTest extends OrmTestCase
// the where clause when not joining onto that table
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c LEFT JOIN Doctrine\Tests\Models\Company\CompanyEmployee e WITH e.id = c.salesPerson WHERE c.completed = true',
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6 FROM company_contracts c0_ LEFT JOIN (company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id) ON (c2_.id = c0_.salesPerson_id) WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6, c0_.salesPerson_id AS salesPerson_id_7 FROM company_contracts c0_ LEFT JOIN (company_employees c1_ INNER JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_managers c3_ ON c1_.id = c3_.id) ON (c2_.id = c0_.salesPerson_id) WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
);
}
@@ -2121,7 +2097,7 @@ class SelectSqlGenerationTest extends OrmTestCase
// via a join association
$this->assertSqlGeneration(
'SELECT c FROM Doctrine\Tests\Models\Company\CompanyContract c JOIN c.salesPerson s WHERE c.completed = true',
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6 FROM company_contracts c0_ INNER JOIN company_employees c1_ ON c0_.salesPerson_id = c1_.id LEFT JOIN company_persons c2_ ON c1_.id = c2_.id WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
"SELECT c0_.id AS id_0, c0_.completed AS completed_1, c0_.fixPrice AS fixPrice_2, c0_.hoursWorked AS hoursWorked_3, c0_.pricePerHour AS pricePerHour_4, c0_.maxPrice AS maxPrice_5, c0_.discr AS discr_6, c0_.salesPerson_id AS salesPerson_id_7 FROM company_contracts c0_ INNER JOIN company_employees c1_ ON c0_.salesPerson_id = c1_.id LEFT JOIN company_persons c2_ ON c1_.id = c2_.id LEFT JOIN company_managers c3_ ON c1_.id = c3_.id WHERE (c0_.completed = 1) AND c0_.discr IN ('fix', 'flexible', 'flexultra')"
);
}
@@ -2133,7 +2109,7 @@ class SelectSqlGenerationTest extends OrmTestCase
// into the ON clause of the join
$this->assertSqlGeneration(
'SELECT e, COUNT(c) FROM Doctrine\Tests\Models\Company\CompanyEmployee e JOIN e.contracts c WHERE e.department = :department',
"SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, COUNT(c2_.id) AS sclr_5, c0_.discr AS discr_6 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id INNER JOIN company_contract_employees c3_ ON c1_.id = c3_.employee_id INNER JOIN company_contracts c2_ ON c2_.id = c3_.contract_id AND c2_.discr IN ('fix', 'flexible', 'flexultra') WHERE c1_.department = ?",
"SELECT c0_.id AS id_0, c0_.name AS name_1, c1_.salary AS salary_2, c1_.department AS department_3, c1_.startDate AS startDate_4, c2_.title AS title_5, COUNT(c3_.id) AS sclr_6, c0_.discr AS discr_7, c0_.spouse_id AS spouse_id_8, c2_.car_id AS car_id_9 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id INNER JOIN company_contract_employees c4_ ON c1_.id = c4_.employee_id INNER JOIN company_contracts c3_ ON c3_.id = c4_.contract_id AND c3_.discr IN ('fix', 'flexible', 'flexultra') WHERE c1_.department = ?",
[],
['department' => 'foobar']
);
@@ -2162,7 +2138,7 @@ class SelectSqlGenerationTest extends OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u AS user, SUM(a.id) AS score FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN Doctrine\Tests\Models\CMS\CmsAddress a WITH a.user = u GROUP BY u HAVING score IS NOT NULL AND score >= 5',
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, SUM(c1_.id) AS sclr_4 FROM cms_users c0_ LEFT JOIN cms_addresses c1_ ON (c1_.user_id = c0_.id) GROUP BY c0_.id, c0_.status, c0_.username, c0_.name, c0_.email_id HAVING sclr_4 IS NOT NULL AND sclr_4 >= 5'
'SELECT c0_.id AS id_0, c0_.status AS status_1, c0_.username AS username_2, c0_.name AS name_3, SUM(c1_.id) AS sclr_4, c0_.email_id AS email_id_5 FROM cms_users c0_ LEFT JOIN cms_addresses c1_ ON (c1_.user_id = c0_.id) GROUP BY c0_.id, c0_.status, c0_.username, c0_.name, c0_.email_id HAVING sclr_4 IS NOT NULL AND sclr_4 >= 5'
);
}
@@ -5,8 +5,12 @@ declare(strict_types=1);
use Doctrine\ORM\Events;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\Tests\ORM\Tools\Export;
use Doctrine\Tests\ORM\Tools\Export\Address;
use Doctrine\Tests\ORM\Tools\Export\AddressListener;
use Doctrine\Tests\ORM\Tools\Export\Cart;
use Doctrine\Tests\ORM\Tools\Export\Group;
use Doctrine\Tests\ORM\Tools\Export\GroupListener;
use Doctrine\Tests\ORM\Tools\Export\Phonenumber;
use Doctrine\Tests\ORM\Tools\Export\UserListener;
$metadata->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_NONE);
@@ -57,13 +61,13 @@ $metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);
$metadata->mapManyToOne(
[
'fieldName' => 'mainGroup',
'targetEntity' => Export\Group::class,
'targetEntity' => Group::class,
]
);
$metadata->mapOneToOne(
[
'fieldName' => 'address',
'targetEntity' => Export\Address::class,
'targetEntity' => Address::class,
'inversedBy' => 'user',
'cascade' =>
[0 => 'persist'],
@@ -84,7 +88,7 @@ $metadata->mapOneToOne(
$metadata->mapOneToOne(
[
'fieldName' => 'cart',
'targetEntity' => Export\Cart::class,
'targetEntity' => Cart::class,
'mappedBy' => 'user',
'cascade' =>
[0 => 'persist'],
@@ -96,7 +100,7 @@ $metadata->mapOneToOne(
$metadata->mapOneToMany(
[
'fieldName' => 'phonenumbers',
'targetEntity' => Export\Phonenumber::class,
'targetEntity' => Phonenumber::class,
'cascade' =>
[
1 => 'persist',
@@ -31,6 +31,7 @@ use Doctrine\Tests\Mocks\ConnectionMock;
use Doctrine\Tests\Mocks\EntityManagerMock;
use Doctrine\Tests\Mocks\EntityPersisterMock;
use Doctrine\Tests\Mocks\UnitOfWorkMock;
use Doctrine\Tests\Models\CMS\CmsGroup;
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\Forum\ForumAvatar;
@@ -866,6 +867,62 @@ class UnitOfWorkTest extends OrmTestCase
$this->expectException(EntityNotFoundException::class);
$this->_unitOfWork->getEntityIdentifier(new stdClass());
}
public function testRemovedEntityIsRemovedFromManyToManyCollection(): void
{
$group = new CmsGroup();
$group->name = 'test';
$this->_unitOfWork->persist($group);
$user = new CmsUser();
$user->name = 'test';
$user->groups->add($group);
$this->_unitOfWork->persist($user);
$this->_unitOfWork->commit();
self::assertFalse($user->groups->isDirty());
$this->_unitOfWork->remove($group);
$this->_unitOfWork->commit();
// Test that the removed entity has been removed from the many to many collection
self::assertEmpty(
$user->groups,
'the removed entity should have been removed from the many to many collection'
);
// Collection is clean, snapshot has been updated
self::assertFalse($user->groups->isDirty());
self::assertEmpty($user->groups->getSnapshot());
}
public function testRemovedEntityIsRemovedFromOneToManyCollection(): void
{
$user = new CmsUser();
$user->name = 'test';
$phonenumber = new CmsPhonenumber();
$phonenumber->phonenumber = '0800-123456';
$user->addPhonenumber($phonenumber);
$this->_unitOfWork->persist($user);
$this->_unitOfWork->persist($phonenumber);
$this->_unitOfWork->commit();
self::assertFalse($user->phonenumbers->isDirty());
$this->_unitOfWork->remove($phonenumber);
$this->_unitOfWork->commit();
// Test that the removed entity has been removed from the one to many collection
self::assertEmpty($user->phonenumbers);
// Collection is clean, snapshot has been updated
self::assertFalse($user->phonenumbers->isDirty());
self::assertEmpty($user->phonenumbers->getSnapshot());
}
}
/** @Entity */