mirror of
https://github.com/doctrine/orm.git
synced 2026-04-25 07:28:04 +02:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e6eef1a97d | |||
| 0efac09141 | |||
| efb6cebd41 | |||
| e4769d3191 | |||
| cf408ad9ae | |||
| 7c29078051 | |||
| 401a0c4fe9 | |||
| dba9d72b2d | |||
| fe0647053a | |||
| 7b3db4a037 | |||
| 1d218bae30 | |||
| 40fbbf4429 | |||
| 6f98147d09 | |||
| cfadb5499d | |||
| 9ce9ae2818 | |||
| fdb9d44538 | |||
| a9fcaf1d18 |
@@ -11,17 +11,23 @@
|
||||
"slug": "latest",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.19",
|
||||
"branchName": "2.19.x",
|
||||
"slug": "2.19",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.18",
|
||||
"branchName": "2.18.x",
|
||||
"slug": "2.18",
|
||||
"upcoming": true
|
||||
"current": true
|
||||
},
|
||||
{
|
||||
"name": "2.17",
|
||||
"branchName": "2.17.x",
|
||||
"slug": "2.17",
|
||||
"current": true
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.16",
|
||||
|
||||
@@ -40,9 +40,5 @@ jobs:
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
- name: "Add dummy title to the sidebar"
|
||||
run: |
|
||||
printf '%s\n%s\n\n%s\n' "Dummy title" "===========" "$(cat docs/en/sidebar.rst)" > docs/en/sidebar.rst
|
||||
|
||||
- name: "Run guides-cli"
|
||||
run: "vendor/bin/guides -vvv --no-progress docs/en 2>&1 | grep -v 'Unknown directive' | ( ! grep WARNING )"
|
||||
run: "vendor/bin/guides -vvv --no-progress docs/en 2>&1 | grep -v 'No template found for rendering directive' | ( ! grep WARNING )"
|
||||
|
||||
@@ -10,7 +10,7 @@ on:
|
||||
- src/**
|
||||
- phpstan*
|
||||
- psalm*
|
||||
- tests/Doctrine/StaticAnalysis/**
|
||||
- tests/StaticAnalysis/**
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
@@ -20,7 +20,7 @@ on:
|
||||
- src/**
|
||||
- phpstan*
|
||||
- psalm*
|
||||
- tests/Doctrine/StaticAnalysis/**
|
||||
- tests/StaticAnalysis/**
|
||||
|
||||
jobs:
|
||||
static-analysis-phpstan:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
| [3.0.x][3.0] | [2.18.x][2.18] | [2.17.x][2.17] |
|
||||
|:----------------:|:----------------:|:----------:|
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.18 image]][2.18] | [![Build status][2.17 image]][2.17] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.18 coverage image]][2.18 coverage] | [![Coverage Status][2.17 coverage image]][2.17 coverage] |
|
||||
| [4.0.x][4.0] | [3.1.x][3.1] | [3.0.x][3.0] | [2.19.x][2.19] | [2.18.x][2.18] |
|
||||
|:------------------------------------------------------:|:------------------------------------------------------:|:-------------------------------------------------------:|:--------------------------------------------------------:|:---------------------------------------------------------:|
|
||||
| [![Build status][4.0 image]][4.0] | [![Build status][3.1 image]][3.1] | [![Build status][3.0 image]][3.0] | [![Build status][2.19 image]][2.19] | [![Build status][2.18 image]][2.18] |
|
||||
| [![Coverage Status][4.0 coverage image]][4.0 coverage] | [![Coverage Status][3.1 coverage image]][3.1 coverage] | [![Coverage Status][3.0 coverage image]][3.0 coverage] | [![Coverage Status][2.19 coverage image]][2.19 coverage] | [![Coverage Status][2.18 coverage image]][2.18 coverage] |
|
||||
|
||||
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
|
||||
|
||||
@@ -18,15 +18,23 @@ without requiring unnecessary code duplication.
|
||||
* [Documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/stable/index.html)
|
||||
|
||||
|
||||
[4.0 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=4.0.x
|
||||
[4.0]: https://github.com/doctrine/orm/tree/4.0.x
|
||||
[4.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/4.0.x/graph/badge.svg
|
||||
[4.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/4.0.x
|
||||
[3.1 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.1.x
|
||||
[3.1]: https://github.com/doctrine/orm/tree/3.1.x
|
||||
[3.1 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.1.x/graph/badge.svg
|
||||
[3.1 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.1.x
|
||||
[3.0 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.0.x
|
||||
[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.19 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.19.x
|
||||
[2.19]: https://github.com/doctrine/orm/tree/2.19.x
|
||||
[2.19 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.19.x/graph/badge.svg
|
||||
[2.19 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.19.x
|
||||
[2.18 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.18.x
|
||||
[2.18]: https://github.com/doctrine/orm/tree/2.18.x
|
||||
[2.18 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.18.x/graph/badge.svg
|
||||
[2.18 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.18.x
|
||||
[2.17 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.17.x
|
||||
[2.17]: https://github.com/doctrine/orm/tree/2.17.x
|
||||
[2.17 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.17.x/graph/badge.svg
|
||||
[2.17 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.17.x
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Implementing ArrayAccess for Domain Objects
|
||||
===========================================
|
||||
|
||||
.. sectionauthor:: Roman Borschel (roman@code-factory.org)
|
||||
.. sectionauthor:: Roman Borschel <roman@code-factory.org>
|
||||
|
||||
This recipe will show you how to implement ArrayAccess for your
|
||||
domain objects in order to allow more uniform access, for example
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Implementing the Notify ChangeTracking Policy
|
||||
=============================================
|
||||
|
||||
.. sectionauthor:: Roman Borschel (roman@code-factory.org)
|
||||
.. sectionauthor:: Roman Borschel <roman@code-factory.org>
|
||||
|
||||
The NOTIFY change-tracking policy is the most effective
|
||||
change-tracking policy provided by Doctrine but it requires some
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ Tutorials
|
||||
Changelogs
|
||||
----------
|
||||
|
||||
* `Upgrade <https://github.com/doctrine/doctrine2/blob/master/UPGRADE.md>`_
|
||||
* `Upgrade <https://github.com/doctrine/orm/blob/HEAD/UPGRADE.md>`_
|
||||
|
||||
Cookbook
|
||||
--------
|
||||
|
||||
@@ -462,7 +462,7 @@ Here is the list of possible generation strategies:
|
||||
a new entity is passed to ``EntityManager#persist``. NONE is the
|
||||
same as leaving off the ``#[GeneratedValue]`` entirely.
|
||||
- ``CUSTOM``: With this option, you can use the ``#[CustomIdGenerator]`` attribute.
|
||||
It will allow you to pass a :ref:`class of your own to generate the identifiers.<annref_customidgenerator>`
|
||||
It will allow you to pass a :ref:`class of your own to generate the identifiers. <annref_customidgenerator>`
|
||||
|
||||
Sequence Generator
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -18,14 +18,20 @@ especially what the strategies presented here provide help with.
|
||||
|
||||
.. note::
|
||||
|
||||
Having an SQL logger enabled when processing batches can have a serious impact on performance and resource usage.
|
||||
To avoid that you should remove the corresponding middleware.
|
||||
To remove all middlewares, you can use this line:
|
||||
Having an SQL logger enabled when processing batches can have a
|
||||
serious impact on performance and resource usage.
|
||||
To avoid that, you should use a PSR logger implementation that can be
|
||||
disabled at runtime.
|
||||
For example, with Monolog, you can use ``Logger::pushHandler()``
|
||||
to push a ``NullHandler`` to the logger instance, and then pop it
|
||||
when you need to enable logging again.
|
||||
|
||||
With DBAL 2, you can disable the SQL logger like below:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$em->getConnection()->getConfiguration()->setMiddlewares([]); // DBAL 3
|
||||
$em->getConnection()->getConfiguration()->setSQLLogger(null); // DBAL 2
|
||||
$em->getConnection()->getConfiguration()->setSQLLogger(null);
|
||||
|
||||
Bulk Inserts
|
||||
------------
|
||||
@@ -188,6 +194,3 @@ problems using the following approach:
|
||||
Iterating results is not possible with queries that
|
||||
fetch-join a collection-valued association. The nature of such SQL
|
||||
result sets is not suitable for incremental hydration.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -131,47 +131,47 @@ There are two ways to set up an event handler:
|
||||
* For *all events* you can create a Lifecycle Event Listener or Subscriber class and register
|
||||
it by calling ``$eventManager->addEventListener()`` or ``eventManager->addEventSubscriber()``,
|
||||
see
|
||||
:ref:`Listening and subscribing to Lifecycle Events<listening-and-subscribing-to-lifecycle-events>`
|
||||
:ref:`Listening and subscribing to Lifecycle Events <listening-and-subscribing-to-lifecycle-events>`
|
||||
* For *some events* (see table below), you can create a *Lifecycle Callback* method in the
|
||||
entity, see :ref:`Lifecycle Callbacks<lifecycle-callbacks>`.
|
||||
entity, see :ref:`Lifecycle Callbacks <lifecycle-callbacks>`.
|
||||
|
||||
.. _reference-events-lifecycle-events:
|
||||
|
||||
Events Overview
|
||||
---------------
|
||||
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| Event | Dispatched by | Lifecycle | Passed |
|
||||
| | | Callback | Argument |
|
||||
+=================================================================+=======================+===========+=====================================+
|
||||
| :ref:`preRemove<reference-events-pre-remove>` | ``$em->remove()`` | Yes | `PreRemoveEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postRemove<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostRemoveEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`prePersist<reference-events-pre-persist>` | ``$em->persist()`` | Yes | `PrePersistEventArgs`_ |
|
||||
| | on *initial* persist | | |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postPersist<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostPersistEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preUpdate<reference-events-pre-update>` | ``$em->flush()`` | Yes | `PreUpdateEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postUpdate<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostUpdateEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postLoad<reference-events-post-load>` | Loading from database | Yes | `PostLoadEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`loadClassMetadata<reference-events-load-class-metadata>` | Loading of mapping | No | `LoadClassMetadataEventArgs`_ |
|
||||
| | metadata | | |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| ``onClassMetadataNotFound`` | ``MappingException`` | No | `OnClassMetadataNotFoundEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preFlush<reference-events-pre-flush>` | ``$em->flush()`` | Yes | `PreFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onFlush<reference-events-on-flush>` | ``$em->flush()`` | No | `OnFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postFlush<reference-events-post-flush>` | ``$em->flush()`` | No | `PostFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onClear<reference-events-on-clear>` | ``$em->clear()`` | No | `OnClearEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| Event | Dispatched by | Lifecycle | Passed |
|
||||
| | | Callback | Argument |
|
||||
+==================================================================+=======================+===========+=====================================+
|
||||
| :ref:`preRemove <reference-events-pre-remove>` | ``$em->remove()`` | Yes | `PreRemoveEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postRemove <reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostRemoveEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`prePersist <reference-events-pre-persist>` | ``$em->persist()`` | Yes | `PrePersistEventArgs`_ |
|
||||
| | on *initial* persist | | |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postPersist <reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostPersistEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preUpdate <reference-events-pre-update>` | ``$em->flush()`` | Yes | `PreUpdateEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postUpdate <reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostUpdateEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postLoad <reference-events-post-load>` | Loading from database | Yes | `PostLoadEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`loadClassMetadata <reference-events-load-class-metadata>` | Loading of mapping | No | `LoadClassMetadataEventArgs`_ |
|
||||
| | metadata | | |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| ``onClassMetadataNotFound`` | ``MappingException`` | No | `OnClassMetadataNotFoundEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preFlush <reference-events-pre-flush>` | ``$em->flush()`` | Yes | `PreFlushEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onFlush <reference-events-on-flush>` | ``$em->flush()`` | No | `OnFlushEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postFlush <reference-events-post-flush>` | ``$em->flush()`` | No | `PostFlushEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onClear <reference-events-on-clear>` | ``$em->clear()`` | No | `OnClearEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
|
||||
.. warning::
|
||||
|
||||
@@ -358,7 +358,7 @@ behaviors across different entity classes.
|
||||
|
||||
Note that they require much more detailed knowledge about the inner
|
||||
workings of the ``EntityManager`` and ``UnitOfWork`` classes. Please
|
||||
read the :ref:`Implementing Event Listeners<reference-events-implementing-listeners>` section
|
||||
read the :ref:`Implementing Event Listeners <reference-events-implementing-listeners>` section
|
||||
carefully if you are trying to write your own listener.
|
||||
|
||||
For event subscribers, there are no surprises. They declare the
|
||||
@@ -471,11 +471,11 @@ prePersist
|
||||
There are two ways for the ``prePersist`` event to be triggered:
|
||||
|
||||
- One is when you call ``EntityManager::persist()``. The
|
||||
event is also called for all :ref:`cascaded associations<transitive-persistence>`.
|
||||
event is also called for all :ref:`cascaded associations <transitive-persistence>`.
|
||||
- The other is inside the ``flush()`` method when changes to associations are computed and
|
||||
this association is marked as :ref:`cascade: persist<transitive-persistence>`. Any new entity found
|
||||
this association is marked as :ref:`cascade: persist <transitive-persistence>`. Any new entity found
|
||||
during this operation is also persisted and ``prePersist`` called
|
||||
on it. This is called :ref:`persistence by reachability<persistence-by-reachability>`.
|
||||
on it. This is called :ref:`persistence by reachability <persistence-by-reachability>`.
|
||||
|
||||
In both cases you get passed a ``PrePersistEventArgs`` instance
|
||||
which has access to the entity and the entity manager.
|
||||
@@ -499,7 +499,7 @@ preRemove
|
||||
|
||||
The ``preRemove`` event is called on every entity immediately when it is passed
|
||||
to the ``EntityManager::remove()`` method. It is cascaded for all
|
||||
associations that are marked as :ref:`cascade: remove<transitive-persistence>`
|
||||
associations that are marked as :ref:`cascade: remove <transitive-persistence>`
|
||||
|
||||
It is not called for a DQL ``DELETE`` statement.
|
||||
|
||||
@@ -547,7 +547,7 @@ entities and their associations have been computed. This means, the
|
||||
- Collections scheduled for removal
|
||||
|
||||
To make use of the ``onFlush`` event you have to be familiar with the
|
||||
internal :ref:`UnitOfWork<unit-of-work>` API, which grants you access to the previously
|
||||
internal :ref:`UnitOfWork <unit-of-work>` API, which grants you access to the previously
|
||||
mentioned sets. See this example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -101,7 +101,7 @@ The many-to-many association is only supporting foreign keys in the table defini
|
||||
To work with many-to-many tables containing extra columns you have to use the
|
||||
foreign keys as primary keys feature of Doctrine ORM.
|
||||
|
||||
See :doc:`the tutorial on composite primary keys for more information<../tutorials/composite-primary-keys>`.
|
||||
See :doc:`the tutorial on composite primary keys for more information <../tutorials/composite-primary-keys>`.
|
||||
|
||||
|
||||
How can i paginate fetch-joined collections?
|
||||
|
||||
@@ -380,7 +380,7 @@ It is not supported to use overrides in entity inheritance scenarios.
|
||||
.. note::
|
||||
|
||||
When using traits, make sure not to miss the warnings given in the
|
||||
:doc:`Limitations and Known Issues</reference/limitations-and-known-issues>` chapter.
|
||||
:doc:`Limitations and Known Issues </reference/limitations-and-known-issues>` chapter.
|
||||
|
||||
|
||||
Association Override
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
:orphan:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
:orphan:
|
||||
|
||||
.. toc::
|
||||
|
||||
.. tocheader:: Tutorials
|
||||
@@ -31,6 +33,7 @@
|
||||
reference/inheritance-mapping
|
||||
reference/working-with-objects
|
||||
reference/working-with-associations
|
||||
reference/typedfieldmapper
|
||||
reference/events
|
||||
reference/unitofwork
|
||||
reference/unitofwork-associations
|
||||
|
||||
@@ -1543,15 +1543,6 @@
|
||||
</PossiblyInvalidPropertyAssignmentValue>
|
||||
</file>
|
||||
<file src="src/Query/AST/Functions/DateAddFunction.php">
|
||||
<ArgumentTypeCoercion>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
</ArgumentTypeCoercion>
|
||||
<PossiblyInvalidPropertyAssignmentValue>
|
||||
<code><![CDATA[$parser->ArithmeticPrimary()]]></code>
|
||||
<code><![CDATA[$parser->ArithmeticPrimary()]]></code>
|
||||
@@ -1572,15 +1563,6 @@
|
||||
</PossiblyInvalidPropertyAssignmentValue>
|
||||
</file>
|
||||
<file src="src/Query/AST/Functions/DateSubFunction.php">
|
||||
<ArgumentTypeCoercion>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
<code><![CDATA[$this->intervalExpression->dispatch($sqlWalker)]]></code>
|
||||
</ArgumentTypeCoercion>
|
||||
<UndefinedPropertyFetch>
|
||||
<code><![CDATA[$this->unit->value]]></code>
|
||||
</UndefinedPropertyFetch>
|
||||
|
||||
@@ -74,7 +74,7 @@ class TrimFunction extends FunctionNode
|
||||
$this->trimChar = $lexer->token->value;
|
||||
}
|
||||
|
||||
if ($this->leading || $this->trailing || $this->both || $this->trimChar) {
|
||||
if ($this->leading || $this->trailing || $this->both || ($this->trimChar !== false)) {
|
||||
$parser->match(Lexer::T_FROM);
|
||||
}
|
||||
|
||||
|
||||
+18
-6
@@ -471,6 +471,10 @@ class SqlWalker implements TreeWalker
|
||||
continue;
|
||||
}
|
||||
|
||||
$sqlTableAlias = $this->useSqlTableAliases
|
||||
? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.'
|
||||
: '';
|
||||
|
||||
$conn = $this->em->getConnection();
|
||||
$values = [];
|
||||
|
||||
@@ -479,14 +483,22 @@ class SqlWalker implements TreeWalker
|
||||
}
|
||||
|
||||
foreach ($class->subClasses as $subclassName) {
|
||||
$values[] = $conn->quote($this->em->getClassMetadata($subclassName)->discriminatorValue);
|
||||
$subclassMetadata = $this->em->getClassMetadata($subclassName);
|
||||
|
||||
// Abstract entity classes show up in the list of subClasses, but may be omitted
|
||||
// from the discriminator map. In that case, they have a null discriminator value.
|
||||
if ($subclassMetadata->discriminatorValue === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$values[] = $conn->quote($subclassMetadata->discriminatorValue);
|
||||
}
|
||||
|
||||
$sqlTableAlias = $this->useSqlTableAliases
|
||||
? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.'
|
||||
: '';
|
||||
|
||||
$sqlParts[] = $sqlTableAlias . $class->getDiscriminatorColumn()['name'] . ' IN (' . implode(', ', $values) . ')';
|
||||
if ($values !== []) {
|
||||
$sqlParts[] = $sqlTableAlias . $class->getDiscriminatorColumn()['name'] . ' IN (' . implode(', ', $values) . ')';
|
||||
} else {
|
||||
$sqlParts[] = '1=0'; // impossible condition
|
||||
}
|
||||
}
|
||||
|
||||
$sql = implode(' AND ', $sqlParts);
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\DBAL\ArrayParameterType;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
use function class_exists;
|
||||
|
||||
/** @group GH-11278 */
|
||||
final class QueryParameterTest extends OrmFunctionalTestCase
|
||||
{
|
||||
/** @var int */
|
||||
private $userId;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
|
||||
parent::setUp();
|
||||
|
||||
$user = new CmsUser();
|
||||
$user->name = 'John Doe';
|
||||
$user->username = 'john';
|
||||
$user2 = new CmsUser();
|
||||
$user2->name = 'Jane Doe';
|
||||
$user2->username = 'jane';
|
||||
$user3 = new CmsUser();
|
||||
$user3->name = 'Just Bill';
|
||||
$user3->username = 'bill';
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->persist($user2);
|
||||
$this->_em->persist($user3);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->userId = $user->id;
|
||||
|
||||
$this->_em->clear();
|
||||
}
|
||||
|
||||
public function testParameterTypeInBuilder(): void
|
||||
{
|
||||
$result = $this->_em->createQueryBuilder()
|
||||
->from(CmsUser::class, 'u')
|
||||
->select('u.name')
|
||||
->where('u.id = :id')
|
||||
->setParameter('id', $this->userId, ParameterType::INTEGER)
|
||||
->getQuery()
|
||||
->getArrayResult();
|
||||
|
||||
self::assertSame([['name' => 'John Doe']], $result);
|
||||
}
|
||||
|
||||
public function testParameterTypeInQuery(): void
|
||||
{
|
||||
$result = $this->_em->createQueryBuilder()
|
||||
->from(CmsUser::class, 'u')
|
||||
->select('u.name')
|
||||
->where('u.id = :id')
|
||||
->getQuery()
|
||||
->setParameter('id', $this->userId, ParameterType::INTEGER)
|
||||
->getArrayResult();
|
||||
|
||||
self::assertSame([['name' => 'John Doe']], $result);
|
||||
}
|
||||
|
||||
public function testDbalTypeStringInBuilder(): void
|
||||
{
|
||||
$result = $this->_em->createQueryBuilder()
|
||||
->from(CmsUser::class, 'u')
|
||||
->select('u.name')
|
||||
->where('u.id = :id')
|
||||
->setParameter('id', $this->userId, Types::INTEGER)
|
||||
->getQuery()
|
||||
->getArrayResult();
|
||||
|
||||
self::assertSame([['name' => 'John Doe']], $result);
|
||||
}
|
||||
|
||||
public function testDbalTypeStringInQuery(): void
|
||||
{
|
||||
$result = $this->_em->createQueryBuilder()
|
||||
->from(CmsUser::class, 'u')
|
||||
->select('u.name')
|
||||
->where('u.id = :id')
|
||||
->getQuery()
|
||||
->setParameter('id', $this->userId, Types::INTEGER)
|
||||
->getArrayResult();
|
||||
|
||||
self::assertSame([['name' => 'John Doe']], $result);
|
||||
}
|
||||
|
||||
public function testArrayParameterTypeInBuilder(): void
|
||||
{
|
||||
$result = $this->_em->createQueryBuilder()
|
||||
->from(CmsUser::class, 'u')
|
||||
->select('u.name')
|
||||
->where('u.username IN (:usernames)')
|
||||
->orderBy('u.username')
|
||||
->setParameter('usernames', ['john', 'jane'], class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY)
|
||||
->getQuery()
|
||||
->getArrayResult();
|
||||
|
||||
self::assertSame([['name' => 'Jane Doe'], ['name' => 'John Doe']], $result);
|
||||
}
|
||||
|
||||
public function testArrayParameterTypeInQuery(): void
|
||||
{
|
||||
$result = $this->_em->createQueryBuilder()
|
||||
->from(CmsUser::class, 'u')
|
||||
->select('u.name')
|
||||
->where('u.username IN (:usernames)')
|
||||
->orderBy('u.username')
|
||||
->getQuery()
|
||||
->setParameter('usernames', ['john', 'jane'], class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY)
|
||||
->getArrayResult();
|
||||
|
||||
self::assertSame([['name' => 'Jane Doe'], ['name' => 'John Doe']], $result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use Generator;
|
||||
|
||||
class GH11199Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpEntitySchema([
|
||||
GH11199Root::class,
|
||||
GH11199Parent::class,
|
||||
GH11199Foo::class,
|
||||
GH11199Baz::class,
|
||||
GH11199AbstractLeaf::class,
|
||||
]);
|
||||
}
|
||||
|
||||
public function dqlStatements(): Generator
|
||||
{
|
||||
yield ['SELECT e FROM ' . GH11199Root::class . ' e', "/WHERE g0_.asset_type IN \('root', 'foo', 'baz'\)$/"];
|
||||
yield ['SELECT e FROM ' . GH11199Parent::class . ' e', "/WHERE g0_.asset_type IN \('foo'\)$/"];
|
||||
yield ['SELECT e FROM ' . GH11199Foo::class . ' e', "/WHERE g0_.asset_type IN \('foo'\)$/"];
|
||||
yield ['SELECT e FROM ' . GH11199Baz::class . ' e', "/WHERE g0_.asset_type IN \('baz'\)$/"];
|
||||
yield ['SELECT e FROM ' . GH11199AbstractLeaf::class . ' e', '/WHERE 1=0/'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dqlStatements
|
||||
*/
|
||||
public function testGH11199(string $dql, string $expectedDiscriminatorValues): void
|
||||
{
|
||||
$query = $this->_em->createQuery($dql);
|
||||
$sql = $query->getSQL();
|
||||
|
||||
self::assertMatchesRegularExpression($expectedDiscriminatorValues, $sql);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
* @ORM\Table(name="gh11199")
|
||||
* @ORM\InheritanceType("SINGLE_TABLE")
|
||||
* @ORM\DiscriminatorColumn(name="asset_type", type="string")
|
||||
* @ORM\DiscriminatorMap({
|
||||
* "root" = "\Doctrine\Tests\ORM\Functional\Ticket\GH11199Root",
|
||||
* "foo" = "\Doctrine\Tests\ORM\Functional\Ticket\GH11199Foo",
|
||||
* "baz" = "\Doctrine\Tests\ORM\Functional\Ticket\GH11199Baz",
|
||||
* })
|
||||
*/
|
||||
class GH11199Root
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue(strategy="IDENTITY")
|
||||
* @ORM\Column(type="integer")
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
private $id = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
*/
|
||||
abstract class GH11199Parent extends GH11199Root
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
*/
|
||||
class GH11199Foo extends GH11199Parent
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
*/
|
||||
class GH11199Baz extends GH11199Root
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
*/
|
||||
abstract class GH11199AbstractLeaf extends GH11199Root
|
||||
{
|
||||
}
|
||||
@@ -172,6 +172,11 @@ class LanguageRecognitionTest extends OrmTestCase
|
||||
$this->assertValidDQL("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM(u.name) = 'someone'");
|
||||
}
|
||||
|
||||
public function testTrimFalsyString(): void
|
||||
{
|
||||
$this->assertValidDQL("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM('0' FROM u.name) = 'someone'");
|
||||
}
|
||||
|
||||
public function testArithmeticExpressionsSupportedInWherePart(): void
|
||||
{
|
||||
$this->assertValidDQL('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000');
|
||||
|
||||
Reference in New Issue
Block a user