mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6307b4fa7d | ||
|
|
5d21bb158b | ||
|
|
71550106d4 | ||
|
|
36011f0d0f | ||
|
|
c97d775370 | ||
|
|
e9f0345a97 | ||
|
|
0feb09d0d6 | ||
|
|
fe5f8bbaa1 | ||
|
|
ecf3cec376 | ||
|
|
0a714db4d9 | ||
|
|
471fda8d0b | ||
|
|
dfe32c2f74 | ||
|
|
c51ba3ce6b | ||
|
|
fe025e8d23 | ||
|
|
ae2957cf7e | ||
|
|
e172b3bf9c | ||
|
|
c9c6e8da2e | ||
|
|
17d28b5c4c | ||
|
|
a2d510c6f4 | ||
|
|
2a4ebca90e | ||
|
|
cc29ae0d36 | ||
|
|
bd4a053d29 | ||
|
|
52fbfb3785 | ||
|
|
c259371e5f | ||
|
|
dcdd58b642 | ||
|
|
7b9c53854f | ||
|
|
cdc5fe11dd | ||
|
|
69ece00564 | ||
|
|
c679d1b007 | ||
|
|
1e15b22dcb | ||
|
|
44057b4683 | ||
|
|
013df03795 | ||
|
|
2d2a34407c | ||
|
|
067ad51b3f | ||
|
|
00c77213fb | ||
|
|
3303cd3b5d | ||
|
|
afcf91e839 | ||
|
|
c61a9b3b6d | ||
|
|
c68b8f90b3 | ||
|
|
aa4f9ce9e9 | ||
|
|
d96fc23327 | ||
|
|
3aed6912a3 | ||
|
|
8ce7b310c5 | ||
|
|
158605bf24 | ||
|
|
2c2ef65817 | ||
|
|
1c33a86983 | ||
|
|
310fe1cccb | ||
|
|
a67f677747 | ||
|
|
ec6d1b9f72 | ||
|
|
d809fed52a | ||
|
|
0e4786dfa8 | ||
|
|
c429262f02 | ||
|
|
f4fdcbcdcb | ||
|
|
b0806469d5 | ||
|
|
14866461c5 |
2
.github/workflows/coding-standards.yml
vendored
2
.github/workflows/coding-standards.yml
vendored
@@ -24,4 +24,4 @@ on:
|
||||
|
||||
jobs:
|
||||
coding-standards:
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.2.1"
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.3.0"
|
||||
|
||||
2
.github/workflows/documentation.yml
vendored
2
.github/workflows/documentation.yml
vendored
@@ -17,4 +17,4 @@ on:
|
||||
jobs:
|
||||
documentation:
|
||||
name: "Documentation"
|
||||
uses: "doctrine/.github/.github/workflows/documentation.yml@7.2.1"
|
||||
uses: "doctrine/.github/.github/workflows/documentation.yml@7.3.0"
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.2.1"
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.3.0"
|
||||
secrets:
|
||||
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
|
||||
@@ -41,14 +41,14 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "^1.13 || ^2",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^12.0",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^13.0",
|
||||
"phpbench/phpbench": "^0.16.10 || ^1.0",
|
||||
"phpstan/extension-installer": "~1.1.0 || ^1.4",
|
||||
"phpstan/phpstan": "~1.4.10 || 2.0.3",
|
||||
"phpstan/phpstan-deprecation-rules": "^1 || ^2",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.7.2",
|
||||
"squizlabs/php_codesniffer": "3.12.0",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0",
|
||||
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0",
|
||||
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0"
|
||||
|
||||
3
docs/.gitignore
vendored
Normal file
3
docs/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
composer.lock
|
||||
vendor/
|
||||
build/
|
||||
24
docs/Makefile
Normal file
24
docs/Makefile
Normal file
@@ -0,0 +1,24 @@
|
||||
# Makefile for Doctrine ORM documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
DOCOPTS =
|
||||
BUILD = vendor/bin/guides
|
||||
BUILDDIR = build
|
||||
|
||||
# Internal variables.
|
||||
ALLGUIDESOPTS = $(DOCOPTS) en/
|
||||
|
||||
.PHONY: help clean html
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
|
||||
clean:
|
||||
-rm -rf ./$(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(BUILD) $(ALLGUIDESOPTS) --output=$(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
@@ -1,18 +1,22 @@
|
||||
# Doctrine ORM Documentation
|
||||
|
||||
The documentation is written in [ReStructured Text](https://docutils.sourceforge.io/rst.html).
|
||||
|
||||
## How to Generate:
|
||||
Using Ubuntu 14.04 LTS:
|
||||
|
||||
1. Run ./bin/install-dependencies.sh
|
||||
2. Run ./bin/generate-docs.sh
|
||||
In the `docs/` folder, run
|
||||
|
||||
It will generate the documentation into the build directory of the checkout.
|
||||
composer update
|
||||
|
||||
Then compile the documentation with:
|
||||
|
||||
## Theme issues
|
||||
make html
|
||||
|
||||
If you get a "Theme error", check if the `en/_theme` subdirectory is empty,
|
||||
in which case you will need to run:
|
||||
This will generate the documentation into the `build` subdirectory.
|
||||
|
||||
1. git submodule init
|
||||
2. git submodule update
|
||||
To browse the documentation, you need to run a webserver:
|
||||
|
||||
cd build/html
|
||||
php -S localhost:8000
|
||||
|
||||
Now the documentation is available at [http://localhost:8000](http://localhost:8000).
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
EXECPATH=`dirname $0`
|
||||
cd $EXECPATH
|
||||
cd ..
|
||||
|
||||
rm build -Rf
|
||||
sphinx-build en build
|
||||
|
||||
sphinx-build -b latex en build/pdf
|
||||
rubber --into build/pdf --pdf build/pdf/Doctrine2ORM.tex
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/bash
|
||||
sudo apt-get update && sudo apt-get install -y python2.7 python-sphinx python-pygments
|
||||
10
docs/composer.json
Normal file
10
docs/composer.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "doctrine/orm-docs",
|
||||
"description": "Documentation for the Object-Relational Mapper\"",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"phpdocumentor/guides-cli": "1.7.1",
|
||||
"phpdocumentor/filesystem": "1.7.1"
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Doctrine2ORM.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Doctrine2ORM.qhc"
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
|
||||
"run these through (pdf)latex."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
44
docs/en/cookbook/generated-columns.rst
Normal file
44
docs/en/cookbook/generated-columns.rst
Normal file
@@ -0,0 +1,44 @@
|
||||
Generated Columns
|
||||
=================
|
||||
|
||||
Generated columns, sometimes also called virtual columns, are populated by
|
||||
the database engine itself. They are a tool for performance optimization, to
|
||||
avoid calculating a value on each query.
|
||||
|
||||
You can define generated columns on entities and have Doctrine map the values
|
||||
to your entity.
|
||||
|
||||
Declaring a generated column
|
||||
----------------------------
|
||||
|
||||
There is no explicit mapping instruction for generated columns. Instead, you
|
||||
specify that the column should not be written to, and define a custom column
|
||||
definition.
|
||||
|
||||
.. literalinclude:: generated-columns/Person.php
|
||||
:language: php
|
||||
|
||||
* ``insertable``, ``updatable``: Setting these to false tells Doctrine to never
|
||||
write this column - writing to a generated column would result in an error
|
||||
from the database.
|
||||
* ``columnDefinition``: We specify the full DDL to create the column. To allow
|
||||
to use database specific features, this attribute does not use Doctrine Query
|
||||
Language but native SQL. Note that you need to reference columns by their
|
||||
database name (either explicitly set in the mapping or per the current
|
||||
:doc:`naming strategy <../reference/namingstrategy>`).
|
||||
Be aware that specifying a column definition makes the ``SchemaTool``
|
||||
completely ignore all other configuration for this column. See also
|
||||
:ref:`#[Column] <attrref_column>`
|
||||
* ``generated``: Specifying that this column is always generated tells Doctrine
|
||||
to update the field on the entity with the value from the database after
|
||||
every write operation.
|
||||
|
||||
Advanced example: Extracting a value from a JSON structure
|
||||
----------------------------------------------------------
|
||||
|
||||
Lets assume we have an entity that stores a blogpost as structured JSON.
|
||||
To avoid extracting all titles on the fly when listing the posts, we create a
|
||||
generated column with the field.
|
||||
|
||||
.. literalinclude:: generated-columns/Article.php
|
||||
:language: php
|
||||
33
docs/en/cookbook/generated-columns/Article.php
Normal file
33
docs/en/cookbook/generated-columns/Article.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity]
|
||||
class Article
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private int $id;
|
||||
|
||||
/**
|
||||
* When working with Postgres, it is recommended to use the jsonb
|
||||
* format for better performance.
|
||||
*/
|
||||
#[ORM\Column(options: ['jsonb' => true])]
|
||||
private array $content;
|
||||
|
||||
/**
|
||||
* Because we specify NOT NULL, inserting will fail if the content does
|
||||
* not have a string in the title field.
|
||||
*/
|
||||
#[ORM\Column(
|
||||
insertable: false,
|
||||
updatable: false,
|
||||
columnDefinition: "VARCHAR(255) generated always as (content->>'title') stored NOT NULL",
|
||||
generated: 'ALWAYS',
|
||||
)]
|
||||
private string $title;
|
||||
}
|
||||
24
docs/en/cookbook/generated-columns/Person.php
Normal file
24
docs/en/cookbook/generated-columns/Person.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity]
|
||||
class Person
|
||||
{
|
||||
#[ORM\Column(type: 'string')]
|
||||
private string $firstName;
|
||||
|
||||
#[ORM\Column(type: 'string', name: 'name')]
|
||||
private string $lastName;
|
||||
|
||||
#[ORM\Column(
|
||||
type: 'string',
|
||||
insertable: false,
|
||||
updatable: false,
|
||||
columnDefinition: "VARCHAR(255) GENERATED ALWAYS AS (concat(firstName, ' ', name) stored NOT NULL",
|
||||
generated: 'ALWAYS',
|
||||
)]
|
||||
private string $fullName;
|
||||
}
|
||||
@@ -103,6 +103,7 @@ Cookbook
|
||||
|
||||
* **Patterns**:
|
||||
:doc:`Aggregate Fields <cookbook/aggregate-fields>` \|
|
||||
:doc:`Generated/Virtual Columns <cookbook/generated-columns>` \|
|
||||
:doc:`Decorator Pattern <cookbook/decorator-pattern>` \|
|
||||
:doc:`Strategy Pattern <cookbook/strategy-cookbook-introduction>`
|
||||
|
||||
@@ -123,4 +124,5 @@ Cookbook
|
||||
|
||||
* **Custom Datatypes**
|
||||
:doc:`MySQL Enums <cookbook/mysql-enums>`
|
||||
:doc:`Custom Mapping Types <cookbook/custom-mapping-types>`
|
||||
:doc:`Advanced Field Value Conversion <cookbook/advanced-field-value-conversion-using-custom-mapping-types>`
|
||||
|
||||
@@ -71,8 +71,8 @@ Configuration Options
|
||||
The following sections describe all the configuration options
|
||||
available on a ``Doctrine\ORM\Configuration`` instance.
|
||||
|
||||
Proxy Directory (***REQUIRED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Proxy Directory (**REQUIRED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -85,8 +85,8 @@ classes. For a detailed explanation on proxy classes and how they
|
||||
are used in Doctrine, refer to the "Proxy Objects" section further
|
||||
down.
|
||||
|
||||
Proxy Namespace (***REQUIRED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Proxy Namespace (**REQUIRED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -98,8 +98,8 @@ Gets or sets the namespace to use for generated proxy classes. For
|
||||
a detailed explanation on proxy classes and how they are used in
|
||||
Doctrine, refer to the "Proxy Objects" section further down.
|
||||
|
||||
Metadata Driver (***REQUIRED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Metadata Driver (**REQUIRED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -144,8 +144,8 @@ accept either a single directory as a string or an array of
|
||||
directories. With this feature a single driver can support multiple
|
||||
directories of Entities.
|
||||
|
||||
Metadata Cache (***RECOMMENDED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Metadata Cache (**RECOMMENDED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -166,8 +166,8 @@ For development you should use an array cache like
|
||||
``Symfony\Component\Cache\Adapter\ArrayAdapter``
|
||||
which only caches data on a per-request basis.
|
||||
|
||||
Query Cache (***RECOMMENDED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Query Cache (**RECOMMENDED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -189,8 +189,8 @@ For development you should use an array cache like
|
||||
``Symfony\Component\Cache\Adapter\ArrayAdapter``
|
||||
which only caches data on a per-request basis.
|
||||
|
||||
SQL Logger (***Optional***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
SQL Logger (**Optional**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -202,8 +202,8 @@ Gets or sets the logger to use for logging all SQL statements
|
||||
executed by Doctrine. The logger class must implement the
|
||||
deprecated ``Doctrine\DBAL\Logging\SQLLogger`` interface.
|
||||
|
||||
Auto-generating Proxy Classes (***OPTIONAL***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Auto-generating Proxy Classes (**OPTIONAL**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Proxy classes can either be generated manually through the Doctrine
|
||||
Console or automatically at runtime by Doctrine. The configuration
|
||||
@@ -446,7 +446,7 @@ correctly if sub-namespaces use different metadata driver
|
||||
implementations.
|
||||
|
||||
|
||||
Default Repository (***OPTIONAL***)
|
||||
Default Repository (**OPTIONAL**)
|
||||
-----------------------------------
|
||||
|
||||
Specifies the FQCN of a subclass of the EntityRepository.
|
||||
@@ -461,7 +461,7 @@ That will be available for all entities without a custom repository class.
|
||||
The default value is ``Doctrine\ORM\EntityRepository``.
|
||||
Any repository class must be a subclass of EntityRepository otherwise you got an ORMException
|
||||
|
||||
Ignoring entities (***OPTIONAL***)
|
||||
Ignoring entities (**OPTIONAL**)
|
||||
-----------------------------------
|
||||
|
||||
Specifies the Entity FQCNs to ignore.
|
||||
|
||||
@@ -1426,7 +1426,7 @@ Is essentially the same as following:
|
||||
<doctrine-mapping>
|
||||
<entity class="Product">
|
||||
<one-to-one field="shipment" target-entity="Shipment">
|
||||
<join-column name="shipment_id" referenced-column-name="id" nulable=false />
|
||||
<join-column name="shipment_id" referenced-column-name="id" nullable=false />
|
||||
</one-to-one>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
@@ -213,12 +213,15 @@ Optional parameters:
|
||||
- ``check``: Adds a check constraint type to the column (might not
|
||||
be supported by all vendors).
|
||||
|
||||
- **columnDefinition**: DDL SQL snippet that starts after the column
|
||||
- **columnDefinition**: Specify the DDL SQL snippet that starts after the column
|
||||
name and specifies the complete (non-portable!) column definition.
|
||||
This attribute allows to make use of advanced RMDBS features.
|
||||
However you should make careful use of this feature and the
|
||||
consequences. ``SchemaTool`` will not detect changes on the column correctly
|
||||
anymore if you use ``columnDefinition``.
|
||||
However, as this needs to be specified in the DDL native to the database,
|
||||
the resulting schema changes are no longer portable. If you specify a
|
||||
``columnDefinition``, the ``SchemaTool`` ignores all other attributes
|
||||
that are normally used to build the definition DDL. Changes to the
|
||||
``columnDefinition`` are not detected, you will need to manually create a
|
||||
migration to apply changes.
|
||||
|
||||
Additionally you should remember that the ``type``
|
||||
attribute still handles the conversion between PHP and Database
|
||||
@@ -261,10 +264,11 @@ Examples:
|
||||
)]
|
||||
protected $loginCount;
|
||||
|
||||
// MySQL example: full_name char(41) GENERATED ALWAYS AS (concat(firstname,' ',lastname)),
|
||||
// columnDefinition is raw SQL, not DQL. This example works for MySQL:
|
||||
#[Column(
|
||||
type: "string",
|
||||
name: "user_fullname",
|
||||
columnDefinition: "VARCHAR(255) GENERATED ALWAYS AS (concat(firstname,' ',lastname))",
|
||||
insertable: false,
|
||||
updatable: false
|
||||
)]
|
||||
@@ -366,7 +370,7 @@ Optional parameters:
|
||||
|
||||
- **type**: By default this is string.
|
||||
- **length**: By default this is 255.
|
||||
- **columnDefinition**: By default this is null the definition according to the type will be used. This option allows to override it.
|
||||
- **columnDefinition**: Allows to override how the column is generated. See the "columnDefinition" attribute on :ref:`#[Column] <attrref_column>`
|
||||
- **enumType**: By default this is `null`. Allows to map discriminatorColumn value to PHP enum
|
||||
- **options**: See "options" attribute on :ref:`#[Column] <attrref_column>`.
|
||||
|
||||
@@ -678,8 +682,10 @@ Optional parameters:
|
||||
- **onDelete**: Cascade Action (Database-level)
|
||||
- **columnDefinition**: DDL SQL snippet that starts after the column
|
||||
name and specifies the complete (non-portable!) column definition.
|
||||
This attribute enables the use of advanced RMDBS features. Using
|
||||
this attribute on ``#[JoinColumn]`` is necessary if you need slightly
|
||||
This attribute enables the use of advanced RMDBS features. Note that you
|
||||
need to reference columns by their database name (either explicitly set in
|
||||
the mapping or per the current :doc:`naming strategy <namingstrategy>`).
|
||||
Using this attribute on ``#[JoinColumn]`` is necessary if you need
|
||||
different column definitions for joining columns, for example
|
||||
regarding NULL/NOT NULL defaults. However by default a
|
||||
"columnDefinition" attribute on :ref:`#[Column] <attrref_column>` also sets
|
||||
|
||||
@@ -299,7 +299,7 @@ specific to a particular entity class's lifecycle.
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="User">
|
||||
|
||||
@@ -323,7 +323,7 @@ level cache region.
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="Country">
|
||||
@@ -431,7 +431,7 @@ It caches the primary keys of association and cache each element will be cached
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="State">
|
||||
|
||||
@@ -736,6 +736,35 @@ methods:
|
||||
|
||||
.. note::
|
||||
|
||||
There is a limitation on the compatibility of Criteria comparisons.
|
||||
You have to use scalar values only as the value in a comparison or
|
||||
the behaviour between different backends is not the same.
|
||||
Depending on whether the collection has already been loaded from the
|
||||
database or not, criteria matching may happen at the database/SQL level
|
||||
or on objects in memory. This may lead to different results and come
|
||||
surprising, for example when a code change in one place leads to a collection
|
||||
becoming initialized and, as a side effect, returning a different result
|
||||
or even breaking a ``matching()`` call somewhere else. Also, collection
|
||||
initialization state in practical use cases may differ from the one covered
|
||||
in unit tests.
|
||||
|
||||
Database level comparisons are based on scalar representations of the values
|
||||
stored in entity properties. The field names passed to expressions correspond
|
||||
to property names. Comparison and sorting may be affected by
|
||||
database-specific behavior. For example, MySQL enum types sort by index position,
|
||||
not lexicographically by value.
|
||||
|
||||
In-memory handling is based on the ``Selectable`` API of `Doctrine Collections <https://www.doctrine-project.org/projects/doctrine-collections/en/stable/index.html#matching>`.
|
||||
In this case, field names passed to expressions are being used to derive accessor
|
||||
method names. Strict type comparisons are used for equal and not-equal checks,
|
||||
and generally PHP language rules are being used for other comparison operators
|
||||
or sorting.
|
||||
|
||||
As a general guidance, for consistent results use the Criteria API with scalar
|
||||
values only. Note that ``DateTime`` and ``DateTimeImmutable`` are two predominant
|
||||
examples of value objects that are *not* scalars.
|
||||
|
||||
Refrain from using special database-level column types or custom Doctrine Types
|
||||
that may lead to database-specific comparison or sorting rules being applied, or
|
||||
to database-level values being different from object field values.
|
||||
|
||||
Provide accessor methods for all entity fields used in criteria expressions,
|
||||
and implement those methods in a way that their return value is the
|
||||
same as the database-level value.
|
||||
|
||||
@@ -17,7 +17,7 @@ setup for the latest code in trunk.
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -103,7 +103,7 @@ of several common elements:
|
||||
// Doctrine.Tests.ORM.Mapping.User.dcm.xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -770,7 +770,7 @@ entity relationship. You can define this in XML with the "association-key" attri
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
cookbook/decorator-pattern
|
||||
cookbook/dql-custom-walkers
|
||||
cookbook/dql-user-defined-functions
|
||||
cookbook/generated-columns
|
||||
cookbook/implementing-arrayaccess-for-domain-objects
|
||||
cookbook/implementing-the-notify-changetracking-policy
|
||||
cookbook/resolve-target-entity-listener
|
||||
|
||||
@@ -86,7 +86,7 @@ and year of production as primary keys:
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -127,11 +127,12 @@ And for querying you can use arrays to both DQL and EntityRepositories:
|
||||
namespace VehicleCatalogue\Model;
|
||||
|
||||
// $em is the EntityManager
|
||||
$audi = $em->find("VehicleCatalogue\Model\Car", array("name" => "Audi A8", "year" => 2010));
|
||||
$audi = $em->find("VehicleCatalogue\Model\Car", ["name" => "Audi A8", "year" => 2010]);
|
||||
|
||||
$dql = "SELECT c FROM VehicleCatalogue\Model\Car c WHERE c.id = ?1";
|
||||
$dql = "SELECT c FROM VehicleCatalogue\Model\Car c WHERE c.name = ?1 AND c.year = ?2";
|
||||
$audi = $em->createQuery($dql)
|
||||
->setParameter(1, ["name" => "Audi A8", "year" => 2010])
|
||||
->setParameter(1, "Audi A8")
|
||||
->setParameter(2, 2010)
|
||||
->getSingleResult();
|
||||
|
||||
You can also use this entity in associations. Doctrine will then generate two foreign keys one for ``name``
|
||||
@@ -268,7 +269,7 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ switch to extra lazy as shown in these examples:
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
|
||||
@@ -558,7 +558,7 @@ methods, but you only need to choose one.
|
||||
|
||||
<!-- config/xml/Product.dcm.xml -->
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -1139,7 +1139,7 @@ the ``Product`` before:
|
||||
|
||||
<!-- config/xml/Bug.dcm.xml -->
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -1294,7 +1294,7 @@ Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
|
||||
<!-- config/xml/User.dcm.xml -->
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -1818,7 +1818,7 @@ we have to adjust the metadata slightly.
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ here are the code and mappings for it:
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ parameters:
|
||||
|
||||
# Fallback logic for DBAL 2
|
||||
-
|
||||
message: '/Application::add\(\) expects Symfony\\Component\\Console\\Command\\Command/'
|
||||
message: '/Parameter #2 \$command of static method Doctrine\\ORM\\Tools\\Console\\ConsoleRunner\:\:addCommandToApplication\(\) expects Symfony\\Component\\Console\\Command\\Command/'
|
||||
path: src/Tools/Console/ConsoleRunner.php
|
||||
|
||||
- '/^Class Doctrine\\DBAL\\Platforms\\SQLAnywherePlatform not found\.$/'
|
||||
|
||||
@@ -9,7 +9,7 @@ parameters:
|
||||
|
||||
# Fallback logic for DBAL 2
|
||||
-
|
||||
message: '/Application::add\(\) expects Symfony\\Component\\Console\\Command\\Command/'
|
||||
message: '/Parameter #2 \$command of static method Doctrine\\ORM\\Tools\\Console\\ConsoleRunner\:\:addCommandToApplication\(\) expects Symfony\\Component\\Console\\Command\\Command/'
|
||||
path: src/Tools/Console/ConsoleRunner.php
|
||||
|
||||
- '/^Class Doctrine\\DBAL\\Platforms\\SQLAnywherePlatform not found\.$/'
|
||||
|
||||
@@ -1109,6 +1109,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
|
||||
public function setLazyGhostObjectEnabled(bool $flag): void
|
||||
{
|
||||
// @phpstan-ignore classConstant.deprecatedTrait (Because we support Symfony < 7.3)
|
||||
if ($flag && ! trait_exists(LazyGhostTrait::class)) {
|
||||
throw new LogicException(
|
||||
'Lazy ghost objects cannot be enabled because the "symfony/var-exporter" library'
|
||||
|
||||
@@ -1278,7 +1278,6 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
/**
|
||||
* @param string $fieldName
|
||||
* @param array $cache
|
||||
* @phpstan-param array{usage?: int|null, region?: string|null} $cache
|
||||
*
|
||||
* @return int[]|string[]
|
||||
|
||||
@@ -309,7 +309,7 @@ EXCEPTION
|
||||
. ' configured to cascade persist operations for entity: ' . self::objToStr($entity) . '.'
|
||||
. ' To solve this issue: Either explicitly call EntityManager#persist()'
|
||||
. ' on this unknown entity or configure cascade persist'
|
||||
. ' this association in the mapping for example @ManyToOne(..,cascade={"persist"}).'
|
||||
. ' this association in the mapping for example #[ORM\ManyToOne(..., cascade: [\'persist\'])].'
|
||||
. (method_exists($entity, '__toString')
|
||||
? ''
|
||||
: ' If you cannot find out which entity causes the problem implement \''
|
||||
|
||||
@@ -226,6 +226,16 @@ class BasicEntityPersister implements EntityPersister
|
||||
);
|
||||
}
|
||||
|
||||
final protected function isFilterHashUpToDate(): bool
|
||||
{
|
||||
return $this->filterHash === $this->em->getFilters()->getHash();
|
||||
}
|
||||
|
||||
final protected function updateFilterHash(): void
|
||||
{
|
||||
$this->filterHash = $this->em->getFilters()->getHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -1274,7 +1284,7 @@ class BasicEntityPersister implements EntityPersister
|
||||
*/
|
||||
protected function getSelectColumnsSQL()
|
||||
{
|
||||
if ($this->currentPersisterContext->selectColumnListSql !== null && $this->filterHash === $this->em->getFilters()->getHash()) {
|
||||
if ($this->currentPersisterContext->selectColumnListSql !== null && $this->isFilterHashUpToDate()) {
|
||||
return $this->currentPersisterContext->selectColumnListSql;
|
||||
}
|
||||
|
||||
@@ -1374,6 +1384,12 @@ class BasicEntityPersister implements EntityPersister
|
||||
$joinCondition[] = $this->getSQLTableAlias($association['sourceEntity'], $assocAlias) . '.' . $sourceCol . ' = '
|
||||
. $this->getSQLTableAlias($association['targetEntity']) . '.' . $targetCol;
|
||||
}
|
||||
|
||||
// Add filter SQL
|
||||
$filterSql = $this->generateFilterConditionSQL($eagerEntity, $joinTableAlias);
|
||||
if ($filterSql) {
|
||||
$joinCondition[] = $filterSql;
|
||||
}
|
||||
}
|
||||
|
||||
$this->currentPersisterContext->selectJoinSql .= ' ' . $joinTableName . ' ' . $joinTableAlias . ' ON ';
|
||||
@@ -1381,7 +1397,7 @@ class BasicEntityPersister implements EntityPersister
|
||||
}
|
||||
|
||||
$this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
|
||||
$this->filterHash = $this->em->getFilters()->getHash();
|
||||
$this->updateFilterHash();
|
||||
|
||||
return $this->currentPersisterContext->selectColumnListSql;
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
protected function getSelectColumnsSQL()
|
||||
{
|
||||
// Create the column list fragment only once
|
||||
if ($this->currentPersisterContext->selectColumnListSql !== null) {
|
||||
if ($this->currentPersisterContext->selectColumnListSql !== null && $this->isFilterHashUpToDate()) {
|
||||
return $this->currentPersisterContext->selectColumnListSql;
|
||||
}
|
||||
|
||||
@@ -495,6 +495,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
|
||||
$this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
|
||||
$this->updateFilterHash();
|
||||
|
||||
return $this->currentPersisterContext->selectColumnListSql;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
*/
|
||||
protected function getSelectColumnsSQL()
|
||||
{
|
||||
if ($this->currentPersisterContext->selectColumnListSql !== null) {
|
||||
if ($this->currentPersisterContext->selectColumnListSql !== null && $this->isFilterHashUpToDate()) {
|
||||
return $this->currentPersisterContext->selectColumnListSql;
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
|
||||
}
|
||||
|
||||
$this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
|
||||
$this->updateFilterHash();
|
||||
|
||||
return $this->currentPersisterContext->selectColumnListSql;
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ EOPHP;
|
||||
$class = $entityPersister->getClassMetadata();
|
||||
|
||||
foreach ($class->getReflectionProperties() as $property) {
|
||||
if (isset($identifier[$property->name]) || ! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) {
|
||||
if (isset($identifier[$property->name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -448,7 +448,7 @@ EOPHP;
|
||||
foreach ($reflector->getProperties($filter) as $property) {
|
||||
$name = $property->name;
|
||||
|
||||
if ($property->isStatic() || (($class->hasField($name) || $class->hasAssociation($name)) && ! isset($identifiers[$name]))) {
|
||||
if ($property->isStatic() || ! isset($identifiers[$name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -568,6 +568,7 @@ EOPHP;
|
||||
|
||||
private function generateUseLazyGhostTrait(ClassMetadata $class): string
|
||||
{
|
||||
// @phpstan-ignore staticMethod.deprecated (Because we support Symfony < 7.3)
|
||||
$code = ProxyHelper::generateLazyGhost($class->getReflectionClass());
|
||||
$code = substr($code, 7 + (int) strpos($code, "\n{"));
|
||||
$code = substr($code, 0, (int) strpos($code, "\n}"));
|
||||
|
||||
@@ -1554,7 +1554,7 @@ class Parser
|
||||
|
||||
assert($this->lexer->lookahead !== null);
|
||||
switch (true) {
|
||||
case $this->isMathOperator($peek):
|
||||
case $this->isMathOperator($peek) || $this->isMathOperator($glimpse):
|
||||
$expr = $this->SimpleArithmeticExpression();
|
||||
break;
|
||||
|
||||
|
||||
28
src/Tools/Console/ApplicationCompatibility.php
Normal file
28
src/Tools/Console/ApplicationCompatibility.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Tools\Console;
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
use function method_exists;
|
||||
|
||||
/**
|
||||
* Forward compatibility with Symfony Console 7.4
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait ApplicationCompatibility
|
||||
{
|
||||
private static function addCommandToApplication(Application $application, Command $command): ?Command
|
||||
{
|
||||
if (method_exists(Application::class, 'addCommand')) {
|
||||
// @phpstan-ignore method.notFound (This method will be added in Symfony 7.4)
|
||||
return $application->addCommand($command);
|
||||
}
|
||||
|
||||
return $application->add($command);
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ EOT
|
||||
|
||||
private function doExecute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$ui = (new SymfonyStyle($input, $output))->getErrorStyle();
|
||||
$ui = new SymfonyStyle($input, $output);
|
||||
|
||||
$entityManager = $this->getEntityManager($input);
|
||||
|
||||
@@ -48,7 +48,7 @@ EOT
|
||||
->getAllClassNames();
|
||||
|
||||
if (! $entityClassNames) {
|
||||
$ui->caution(
|
||||
$ui->getErrorStyle()->caution(
|
||||
[
|
||||
'You do not have any mapped Doctrine ORM entities according to the current configuration.',
|
||||
'If you have entities or mapping files you should check your mapping configuration for errors.',
|
||||
|
||||
@@ -65,7 +65,7 @@ EOT
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$ui = (new SymfonyStyle($input, $output))->getErrorStyle();
|
||||
$ui = new SymfonyStyle($input, $output);
|
||||
|
||||
$entityManager = $this->getEntityManager($input);
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ use function class_exists;
|
||||
*/
|
||||
final class ConsoleRunner
|
||||
{
|
||||
use ApplicationCompatibility;
|
||||
|
||||
/**
|
||||
* Create a Symfony Console HelperSet
|
||||
*
|
||||
@@ -91,7 +93,7 @@ final class ConsoleRunner
|
||||
$connectionProvider = new ConnectionFromManagerProvider($entityManagerProvider);
|
||||
|
||||
if (class_exists(DBALConsole\Command\ImportCommand::class)) {
|
||||
$cli->add(new DBALConsole\Command\ImportCommand());
|
||||
self::addCommandToApplication($cli, new DBALConsole\Command\ImportCommand());
|
||||
}
|
||||
|
||||
$cli->addCommands(
|
||||
|
||||
@@ -105,17 +105,24 @@ class LimitSubqueryOutputWalker extends SqlOutputWalker
|
||||
$this->platform = $query->getEntityManager()->getConnection()->getDatabasePlatform();
|
||||
$this->rsm = $parserResult->getResultSetMapping();
|
||||
|
||||
$query = clone $query;
|
||||
$cloneQuery = clone $query;
|
||||
|
||||
$cloneQuery->setParameters(clone $query->getParameters());
|
||||
$cloneQuery->setCacheable(false);
|
||||
|
||||
foreach ($query->getHints() as $name => $value) {
|
||||
$cloneQuery->setHint($name, $value);
|
||||
}
|
||||
|
||||
// Reset limit and offset
|
||||
$this->firstResult = $query->getFirstResult();
|
||||
$this->maxResults = $query->getMaxResults();
|
||||
$query->setFirstResult(0)->setMaxResults(null);
|
||||
$this->firstResult = $cloneQuery->getFirstResult();
|
||||
$this->maxResults = $cloneQuery->getMaxResults();
|
||||
$cloneQuery->setFirstResult(0)->setMaxResults(null);
|
||||
|
||||
$this->em = $query->getEntityManager();
|
||||
$this->em = $cloneQuery->getEntityManager();
|
||||
$this->quoteStrategy = $this->em->getConfiguration()->getQuoteStrategy();
|
||||
|
||||
parent::__construct($query, $parserResult, $queryComponents);
|
||||
parent::__construct($cloneQuery, $parserResult, $queryComponents);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,7 @@ use Doctrine\Persistence\PropertyChangedListener;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\VarExporter\Hydrator;
|
||||
use UnexpectedValueException;
|
||||
|
||||
use function array_chunk;
|
||||
@@ -2944,6 +2945,11 @@ EXCEPTION
|
||||
|
||||
if ($this->isUninitializedObject($entity)) {
|
||||
$entity->__setInitialized(true);
|
||||
|
||||
if ($this->em->getConfiguration()->isLazyGhostObjectEnabled()) {
|
||||
// Initialize properties that have default values to their default value (similar to what
|
||||
Hydrator::hydrate($entity, (array) $class->reflClass->newInstanceWithoutConstructor());
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
! isset($hints[Query::HINT_REFRESH])
|
||||
|
||||
238
tests/Doctrine/Tests/ORM/Functional/GH8011Test.php
Normal file
238
tests/Doctrine/Tests/ORM/Functional/GH8011Test.php
Normal file
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
|
||||
use Doctrine\Tests\Models\Company\CompanyEmployee;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Functional tests for ordering with arithmetic expression.
|
||||
*
|
||||
* @group GH8011
|
||||
*/
|
||||
class GH8011Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->useModelSet('company');
|
||||
|
||||
parent::setUp();
|
||||
|
||||
$this->generateFixture();
|
||||
}
|
||||
|
||||
private function skipIfPostgres(string $test): void
|
||||
{
|
||||
$platform = $this->_em->getConnection()->getDatabasePlatform();
|
||||
if ($platform instanceof PostgreSQLPlatform) {
|
||||
self::markTestSkipped(
|
||||
'The ' . $test . ' test does not work on postgresql (see https://github.com/doctrine/orm/pull/8012).'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithSingleValuedPathExpression(): void
|
||||
{
|
||||
$dql = 'SELECT p ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY p.id + p.id ASC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Benjamin E.', $result[0]->getName());
|
||||
$this->assertEquals('Guilherme B.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithLiteralAndSingleValuedPathExpression(): void
|
||||
{
|
||||
$dql = 'SELECT p ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY 1 + p.id ASC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Benjamin E.', $result[0]->getName());
|
||||
$this->assertEquals('Guilherme B.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithLiteralAndSingleValuedPathExpression2(): void
|
||||
{
|
||||
$dql = 'SELECT p ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY ((1 + p.id)) ASC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Benjamin E.', $result[0]->getName());
|
||||
$this->assertEquals('Guilherme B.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithSingleValuedPathExpressionAndLiteral(): void
|
||||
{
|
||||
$dql = 'SELECT p ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY p.id + 1 ASC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Benjamin E.', $result[0]->getName());
|
||||
$this->assertEquals('Guilherme B.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithResultVariableAndLiteral(): void
|
||||
{
|
||||
$this->skipIfPostgres(__FUNCTION__);
|
||||
|
||||
$dql = 'SELECT p, p.salary AS HIDDEN s ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY s + 1 DESC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Guilherme B.', $result[0]->getName());
|
||||
$this->assertEquals('Benjamin E.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithResultVariableAndLiteral2(): void
|
||||
{
|
||||
$this->skipIfPostgres(__FUNCTION__);
|
||||
|
||||
$dql = 'SELECT p, p.salary AS HIDDEN s ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY ((s + 1)) DESC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Guilherme B.', $result[0]->getName());
|
||||
$this->assertEquals('Benjamin E.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithLiteralAndResultVariable(): void
|
||||
{
|
||||
$this->skipIfPostgres(__FUNCTION__);
|
||||
|
||||
$dql = 'SELECT p, p.salary AS HIDDEN s ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY 1 + s DESC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Guilherme B.', $result[0]->getName());
|
||||
$this->assertEquals('Benjamin E.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithLiteralAndResultVariable2(): void
|
||||
{
|
||||
$this->skipIfPostgres(__FUNCTION__);
|
||||
|
||||
$dql = 'SELECT p, p.salary AS HIDDEN s ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY ((1 + s)) DESC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Guilherme B.', $result[0]->getName());
|
||||
$this->assertEquals('Benjamin E.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithResultVariableAndSingleValuedPathExpression(): void
|
||||
{
|
||||
$this->skipIfPostgres(__FUNCTION__);
|
||||
|
||||
$dql = 'SELECT p, p.salary AS HIDDEN s ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY s + p.id DESC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Guilherme B.', $result[0]->getName());
|
||||
$this->assertEquals('Benjamin E.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithResultVariableAndSingleValuedPathExpression2(): void
|
||||
{
|
||||
$this->skipIfPostgres(__FUNCTION__);
|
||||
|
||||
$dql = 'SELECT p, p.salary AS HIDDEN s ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY ((s + p.id)) DESC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Guilherme B.', $result[0]->getName());
|
||||
$this->assertEquals('Benjamin E.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithSingleValuedPathExpressionAndResultVariable(): void
|
||||
{
|
||||
$this->skipIfPostgres(__FUNCTION__);
|
||||
|
||||
$dql = 'SELECT p, p.salary AS HIDDEN s ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY p.id + s DESC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Guilherme B.', $result[0]->getName());
|
||||
$this->assertEquals('Benjamin E.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function testOrderWithArithmeticExpressionWithLiteralAndResultVariableUsingHiddenResultVariable(): void
|
||||
{
|
||||
$dql = 'SELECT p, 1 + p.salary AS HIDDEN _order ' .
|
||||
'FROM Doctrine\Tests\Models\Company\CompanyEmployee p ' .
|
||||
'ORDER BY _order DESC';
|
||||
|
||||
/** @var CompanyEmployee[] $result */
|
||||
$result = $this->_em->createQuery($dql)->getResult();
|
||||
|
||||
$this->assertEquals(2, count($result));
|
||||
$this->assertEquals('Guilherme B.', $result[0]->getName());
|
||||
$this->assertEquals('Benjamin E.', $result[1]->getName());
|
||||
}
|
||||
|
||||
public function generateFixture(): void
|
||||
{
|
||||
$person1 = new CompanyEmployee();
|
||||
$person1->setName('Benjamin E.');
|
||||
$person1->setDepartment('IT');
|
||||
$person1->setSalary(200000);
|
||||
|
||||
$person2 = new CompanyEmployee();
|
||||
$person2->setName('Guilherme B.');
|
||||
$person2->setDepartment('IT2');
|
||||
$person2->setSalary(400000);
|
||||
|
||||
$this->_em->persist($person1);
|
||||
$this->_em->persist($person2);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
}
|
||||
}
|
||||
@@ -118,13 +118,11 @@ class ConnectionMock extends Connection
|
||||
$this->_platformMock = $platform;
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
public function getExecuteStatements(): array
|
||||
{
|
||||
return $this->_executeStatements;
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
public function getDeletes(): array
|
||||
{
|
||||
return $this->_deletes;
|
||||
|
||||
31
tests/Tests/Models/GH11524/GH11524Entity.php
Normal file
31
tests/Tests/Models/GH11524/GH11524Entity.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\GH11524;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="gh11524_entities")
|
||||
*/
|
||||
class GH11524Entity
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
public $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="GH11524Relation")
|
||||
* @ORM\JoinColumn(name="relation_id", referencedColumnName="id", nullable=true)
|
||||
*
|
||||
* @var GH11524Relation|null
|
||||
*/
|
||||
public $relation = null;
|
||||
}
|
||||
21
tests/Tests/Models/GH11524/GH11524Listener.php
Normal file
21
tests/Tests/Models/GH11524/GH11524Listener.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\GH11524;
|
||||
|
||||
use Doctrine\ORM\Event\PostLoadEventArgs;
|
||||
|
||||
class GH11524Listener
|
||||
{
|
||||
public function postLoad(PostloadEventArgs $eventArgs): void
|
||||
{
|
||||
$object = $eventArgs->getObject();
|
||||
|
||||
if (! $object instanceof GH11524Relation) {
|
||||
return;
|
||||
}
|
||||
|
||||
$object->setCurrentLocale('en');
|
||||
}
|
||||
}
|
||||
50
tests/Tests/Models/GH11524/GH11524Relation.php
Normal file
50
tests/Tests/Models/GH11524/GH11524Relation.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\GH11524;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="gh11524_relations")
|
||||
*/
|
||||
class GH11524Relation
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $currentLocale;
|
||||
|
||||
public function setCurrentLocale(string $locale): void
|
||||
{
|
||||
$this->currentLocale = $locale;
|
||||
}
|
||||
|
||||
public function getTranslation(): string
|
||||
{
|
||||
if ($this->currentLocale === null) {
|
||||
throw new LogicException('The current locale must be set to retrieve translation.');
|
||||
}
|
||||
|
||||
return 'fake';
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,11 @@ namespace Doctrine\Tests\ORM\Functional;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
use function count;
|
||||
use function iterator_to_array;
|
||||
|
||||
class EagerFetchCollectionTest extends OrmFunctionalTestCase
|
||||
{
|
||||
@@ -96,6 +98,16 @@ class EagerFetchCollectionTest extends OrmFunctionalTestCase
|
||||
$this->assertIsString($query->getSql());
|
||||
}
|
||||
|
||||
public function testSubselectFetchJoinWithAllowedWhenOverriddenNotEagerPaginator(): void
|
||||
{
|
||||
$query = $this->_em->createQuery('SELECT o, c FROM ' . EagerFetchOwner::class . ' o JOIN o.children c WITH c.id = 1');
|
||||
$query->setMaxResults(1);
|
||||
$query->setFetchMode(EagerFetchChild::class, 'owner', ORM\ClassMetadata::FETCH_LAZY);
|
||||
|
||||
$paginator = new Paginator($query, true);
|
||||
$this->assertIsArray(iterator_to_array($paginator));
|
||||
}
|
||||
|
||||
public function testEagerFetchWithIterable(): void
|
||||
{
|
||||
$this->createOwnerWithChildren(2);
|
||||
|
||||
@@ -66,10 +66,11 @@ class LifecycleCallbackTest extends OrmFunctionalTestCase
|
||||
self::assertTrue($entity->postPersistCallbackInvoked);
|
||||
|
||||
$this->_em->clear();
|
||||
LifecycleCallbackTestEntity::$postLoadCallbackInvoked = false; // Reset the tracking of the postLoad invocation
|
||||
|
||||
$query = $this->_em->createQuery('select e from Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity e');
|
||||
$result = $query->getResult();
|
||||
self::assertTrue($result[0]->postLoadCallbackInvoked);
|
||||
self::assertTrue($result[0]::$postLoadCallbackInvoked);
|
||||
|
||||
$result[0]->value = 'hello again';
|
||||
|
||||
@@ -130,12 +131,14 @@ class LifecycleCallbackTest extends OrmFunctionalTestCase
|
||||
$id = $entity->getId();
|
||||
|
||||
$this->_em->clear();
|
||||
LifecycleCallbackTestEntity::$postLoadCallbackInvoked = false; // Reset the tracking of the postLoad invocation
|
||||
|
||||
$reference = $this->_em->getReference(LifecycleCallbackTestEntity::class, $id);
|
||||
self::assertFalse($reference->postLoadCallbackInvoked);
|
||||
self::assertFalse($reference::$postLoadCallbackInvoked);
|
||||
$this->assertTrue($this->isUninitializedObject($reference));
|
||||
|
||||
$reference->getValue(); // trigger proxy load
|
||||
self::assertTrue($reference->postLoadCallbackInvoked);
|
||||
self::assertTrue($reference::$postLoadCallbackInvoked);
|
||||
}
|
||||
|
||||
/** @group DDC-958 */
|
||||
@@ -148,13 +151,14 @@ class LifecycleCallbackTest extends OrmFunctionalTestCase
|
||||
$id = $entity->getId();
|
||||
|
||||
$this->_em->clear();
|
||||
LifecycleCallbackTestEntity::$postLoadCallbackInvoked = false; // Reset the tracking of the postLoad invocation
|
||||
|
||||
$reference = $this->_em->find(LifecycleCallbackTestEntity::class, $id);
|
||||
self::assertTrue($reference->postLoadCallbackInvoked);
|
||||
$reference->postLoadCallbackInvoked = false;
|
||||
self::assertTrue($reference::$postLoadCallbackInvoked);
|
||||
$reference::$postLoadCallbackInvoked = false;
|
||||
|
||||
$this->_em->refresh($reference);
|
||||
self::assertTrue($reference->postLoadCallbackInvoked, 'postLoad should be invoked when refresh() is called.');
|
||||
self::assertTrue($reference::$postLoadCallbackInvoked, 'postLoad should be invoked when refresh() is called.');
|
||||
}
|
||||
|
||||
/** @group DDC-113 */
|
||||
@@ -197,6 +201,7 @@ class LifecycleCallbackTest extends OrmFunctionalTestCase
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
LifecycleCallbackTestEntity::$postLoadCallbackInvoked = false; // Reset the tracking of the postLoad invocation
|
||||
|
||||
$dql = <<<'DQL'
|
||||
SELECT
|
||||
@@ -214,9 +219,9 @@ DQL;
|
||||
->createQuery(sprintf($dql, $e1->getId(), $e2->getId()))
|
||||
->getResult();
|
||||
|
||||
self::assertTrue(current($entities)->postLoadCallbackInvoked);
|
||||
self::assertTrue(current($entities)::$postLoadCallbackInvoked);
|
||||
self::assertTrue(current($entities)->postLoadCascaderNotNull);
|
||||
self::assertTrue(current($entities)->cascader->postLoadCallbackInvoked);
|
||||
self::assertTrue(current($entities)->cascader::$postLoadCallbackInvoked);
|
||||
self::assertEquals(current($entities)->cascader->postLoadEntitiesCount, 2);
|
||||
}
|
||||
|
||||
@@ -239,6 +244,8 @@ DQL;
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
LifecycleCallbackTestEntity::$postLoadCallbackInvoked = false; // Reset the tracking of the postLoad invocation
|
||||
LifecycleCallbackCascader::$postLoadCallbackInvoked = false;
|
||||
|
||||
$dql = <<<'DQL'
|
||||
SELECT
|
||||
@@ -256,7 +263,7 @@ DQL;
|
||||
$result = iterator_to_array($query->iterate());
|
||||
|
||||
foreach ($result as $entity) {
|
||||
self::assertTrue($entity[0]->postLoadCallbackInvoked);
|
||||
self::assertTrue($entity[0]::$postLoadCallbackInvoked);
|
||||
self::assertFalse($entity[0]->postLoadCascaderNotNull);
|
||||
|
||||
break;
|
||||
@@ -265,7 +272,7 @@ DQL;
|
||||
$iterableResult = iterator_to_array($query->toIterable());
|
||||
|
||||
foreach ($iterableResult as $entity) {
|
||||
self::assertTrue($entity->postLoadCallbackInvoked);
|
||||
self::assertTrue($entity::$postLoadCallbackInvoked);
|
||||
self::assertFalse($entity->postLoadCascaderNotNull);
|
||||
|
||||
break;
|
||||
@@ -283,6 +290,7 @@ DQL;
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
LifecycleCallbackTestEntity::$postLoadCallbackInvoked = false; // Reset the tracking of the postLoad invocation
|
||||
|
||||
$query = $this->_em->createQuery(
|
||||
'SELECT e FROM Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity AS e'
|
||||
@@ -291,7 +299,7 @@ DQL;
|
||||
$result = iterator_to_array($query->iterate(null, Query::HYDRATE_SIMPLEOBJECT));
|
||||
|
||||
foreach ($result as $entity) {
|
||||
self::assertTrue($entity[0]->postLoadCallbackInvoked);
|
||||
self::assertTrue($entity[0]::$postLoadCallbackInvoked);
|
||||
self::assertFalse($entity[0]->postLoadCascaderNotNull);
|
||||
|
||||
break;
|
||||
@@ -300,7 +308,7 @@ DQL;
|
||||
$result = iterator_to_array($query->toIterable([], Query::HYDRATE_SIMPLEOBJECT));
|
||||
|
||||
foreach ($result as $entity) {
|
||||
self::assertTrue($entity->postLoadCallbackInvoked);
|
||||
self::assertTrue($entity::$postLoadCallbackInvoked);
|
||||
self::assertFalse($entity->postLoadCascaderNotNull);
|
||||
|
||||
break;
|
||||
@@ -325,6 +333,8 @@ DQL;
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
LifecycleCallbackTestEntity::$postLoadCallbackInvoked = false; // Reset the tracking of the postLoad invocation
|
||||
LifecycleCallbackCascader::$postLoadCallbackInvoked = false;
|
||||
|
||||
$dql = <<<'DQL'
|
||||
SELECT
|
||||
@@ -342,9 +352,9 @@ DQL;
|
||||
->createQuery($dql)->setParameter('entA_id', $entA->getId())
|
||||
->getOneOrNullResult();
|
||||
|
||||
self::assertTrue($fetchedA->postLoadCallbackInvoked);
|
||||
self::assertTrue($fetchedA::$postLoadCallbackInvoked);
|
||||
foreach ($fetchedA->entities as $fetchJoinedEntB) {
|
||||
self::assertTrue($fetchJoinedEntB->postLoadCallbackInvoked);
|
||||
self::assertTrue($fetchJoinedEntB::$postLoadCallbackInvoked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +502,7 @@ class LifecycleCallbackTestEntity
|
||||
public $postPersistCallbackInvoked = false;
|
||||
|
||||
/** @var bool */
|
||||
public $postLoadCallbackInvoked = false;
|
||||
public static $postLoadCallbackInvoked = false;
|
||||
|
||||
/** @var bool */
|
||||
public $postLoadCascaderNotNull = false;
|
||||
@@ -546,7 +556,7 @@ class LifecycleCallbackTestEntity
|
||||
/** @PostLoad */
|
||||
public function doStuffOnPostLoad(): void
|
||||
{
|
||||
$this->postLoadCallbackInvoked = true;
|
||||
self::$postLoadCallbackInvoked = true;
|
||||
$this->postLoadCascaderNotNull = isset($this->cascader);
|
||||
}
|
||||
|
||||
@@ -572,7 +582,7 @@ class LifecycleCallbackCascader
|
||||
{
|
||||
/* test stuff */
|
||||
/** @var bool */
|
||||
public $postLoadCallbackInvoked = false;
|
||||
public static $postLoadCallbackInvoked = false;
|
||||
|
||||
/** @var int */
|
||||
public $postLoadEntitiesCount = 0;
|
||||
@@ -599,7 +609,7 @@ class LifecycleCallbackCascader
|
||||
/** @PostLoad */
|
||||
public function doStuffOnPostLoad(): void
|
||||
{
|
||||
$this->postLoadCallbackInvoked = true;
|
||||
self::$postLoadCallbackInvoked = true;
|
||||
$this->postLoadEntitiesCount = count($this->entities);
|
||||
}
|
||||
|
||||
|
||||
@@ -558,7 +558,9 @@ class QueryTest extends OrmFunctionalTestCase
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$data = $this->_em->createQuery('SELECT u FROM ' . CmsUser::class . ' u')
|
||||
$query = 'SELECT u FROM ' . CmsUser::class . ' u ORDER BY u.username';
|
||||
|
||||
$data = $this->_em->createQuery($query)
|
||||
->setFirstResult(1)
|
||||
->setMaxResults(2)
|
||||
->getResult();
|
||||
@@ -567,7 +569,7 @@ class QueryTest extends OrmFunctionalTestCase
|
||||
self::assertEquals('gblanco1', $data[0]->username);
|
||||
self::assertEquals('gblanco2', $data[1]->username);
|
||||
|
||||
$data = $this->_em->createQuery('SELECT u FROM ' . CmsUser::class . ' u')
|
||||
$data = $this->_em->createQuery($query)
|
||||
->setFirstResult(3)
|
||||
->setMaxResults(2)
|
||||
->getResult();
|
||||
@@ -576,7 +578,7 @@ class QueryTest extends OrmFunctionalTestCase
|
||||
self::assertEquals('gblanco3', $data[0]->username);
|
||||
self::assertEquals('gblanco4', $data[1]->username);
|
||||
|
||||
$data = $this->_em->createQuery('SELECT u FROM ' . CmsUser::class . ' u')
|
||||
$data = $this->_em->createQuery($query)
|
||||
->setFirstResult(3)
|
||||
->setMaxResults(2)
|
||||
->getScalarResult();
|
||||
|
||||
@@ -537,6 +537,21 @@ class SQLFilterTest extends OrmFunctionalTestCase
|
||||
self::assertEquals(2, count($query->getResult()));
|
||||
}
|
||||
|
||||
public function testOneToOneInverseSideWithFilter(): void
|
||||
{
|
||||
$this->loadFixtureData();
|
||||
|
||||
$conf = $this->_em->getConfiguration();
|
||||
$conf->addFilter('country', '\Doctrine\Tests\ORM\Functional\CMSCountryFilter');
|
||||
$this->_em->getFilters()->enable('country')->setParameterList('country', ['Germany'], Types::STRING);
|
||||
|
||||
$user = $this->_em->find(CmsUser::class, $this->userId);
|
||||
self::assertNotEmpty($user->address);
|
||||
|
||||
$user2 = $this->_em->find(CmsUser::class, $this->userId2);
|
||||
self::assertEmpty($user2->address);
|
||||
}
|
||||
|
||||
public function testManyToManyFilter(): void
|
||||
{
|
||||
$this->loadFixtureData();
|
||||
|
||||
@@ -51,15 +51,20 @@ class DDC1690Test extends OrmFunctionalTestCase
|
||||
$parentId = $parent->getId();
|
||||
$childId = $child->getId();
|
||||
unset($parent, $child);
|
||||
DDC1690Parent::$addPropertyChangedListenerInvoked = false;
|
||||
DDC1690Child::$addPropertyChangedListenerInvoked = false;
|
||||
|
||||
$parent = $this->_em->find(DDC1690Parent::class, $parentId);
|
||||
$child = $this->_em->find(DDC1690Child::class, $childId);
|
||||
|
||||
self::assertTrue($parent::$addPropertyChangedListenerInvoked);
|
||||
self::assertEquals(1, count($parent->listeners));
|
||||
self::assertCount(0, $child->listeners);
|
||||
$this->assertTrue($this->isUninitializedObject($child));
|
||||
self::assertFalse($child::$addPropertyChangedListenerInvoked);
|
||||
|
||||
$this->_em->getUnitOfWork()->initializeObject($child);
|
||||
|
||||
self::assertTrue($child::$addPropertyChangedListenerInvoked);
|
||||
self::assertCount(1, $child->listeners);
|
||||
unset($parent, $child);
|
||||
|
||||
@@ -106,6 +111,11 @@ class NotifyBaseEntity implements NotifyPropertyChanged
|
||||
*/
|
||||
class DDC1690Parent extends NotifyBaseEntity
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public static $addPropertyChangedListenerInvoked = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @Id
|
||||
@@ -151,11 +161,23 @@ class DDC1690Parent extends NotifyBaseEntity
|
||||
{
|
||||
return $this->child;
|
||||
}
|
||||
|
||||
public function addPropertyChangedListener(PropertyChangedListener $listener): void
|
||||
{
|
||||
self::$addPropertyChangedListenerInvoked = true;
|
||||
|
||||
parent::addPropertyChangedListener($listener);
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class DDC1690Child extends NotifyBaseEntity
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public static $addPropertyChangedListenerInvoked = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @Id
|
||||
@@ -201,4 +223,11 @@ class DDC1690Child extends NotifyBaseEntity
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
public function addPropertyChangedListener(PropertyChangedListener $listener): void
|
||||
{
|
||||
self::$addPropertyChangedListenerInvoked = true;
|
||||
|
||||
parent::addPropertyChangedListener($listener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,16 +57,17 @@ class DDC2230Test extends OrmFunctionalTestCase
|
||||
$this->_em->persist($insertedAddress);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
DDC2230Address::$listener = null; // Reset the tracking state
|
||||
|
||||
$addressProxy = $this->_em->getReference(DDC2230Address::class, $insertedAddress->id);
|
||||
assert($addressProxy instanceof DDC2230Address);
|
||||
|
||||
self::assertTrue($this->isUninitializedObject($addressProxy));
|
||||
self::assertNull($addressProxy->listener);
|
||||
self::assertNull($addressProxy::$listener);
|
||||
|
||||
$this->_em->getUnitOfWork()->initializeObject($addressProxy);
|
||||
|
||||
self::assertSame($this->_em->getUnitOfWork(), $addressProxy->listener);
|
||||
self::assertSame($this->_em->getUnitOfWork(), $addressProxy::$listener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,12 +103,12 @@ class DDC2230Address implements NotifyPropertyChanged
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/** @var \Doctrine\Common\PropertyChangedListener */
|
||||
public $listener;
|
||||
/** @var \Doctrine\Common\PropertyChangedListener|null */
|
||||
public static $listener;
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public function addPropertyChangedListener(PropertyChangedListener $listener)
|
||||
{
|
||||
$this->listener = $listener;
|
||||
self::$listener = $listener;
|
||||
}
|
||||
}
|
||||
|
||||
49
tests/Tests/ORM/Functional/Ticket/GH11524Test.php
Normal file
49
tests/Tests/ORM/Functional/Ticket/GH11524Test.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\Tests\Models\GH11524\GH11524Entity;
|
||||
use Doctrine\Tests\Models\GH11524\GH11524Listener;
|
||||
use Doctrine\Tests\Models\GH11524\GH11524Relation;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
class GH11524Test extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->createSchemaForModels(
|
||||
GH11524Entity::class,
|
||||
GH11524Relation::class
|
||||
);
|
||||
|
||||
$this->_em->getEventManager()->addEventListener(Events::postLoad, new GH11524Listener());
|
||||
}
|
||||
|
||||
public function testPostLoadCalledOnProxy(): void
|
||||
{
|
||||
$relation = new GH11524Relation();
|
||||
$relation->name = 'test';
|
||||
$this->_em->persist($relation);
|
||||
|
||||
$entity = new GH11524Entity();
|
||||
$entity->relation = $relation;
|
||||
|
||||
$this->_em->persist($entity);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$reloadedEntity = $this->_em->find(GH11524Entity::class, $entity->id);
|
||||
|
||||
$reloadedRelation = $reloadedEntity->relation;
|
||||
|
||||
$this->assertTrue($this->isUninitializedObject($reloadedRelation));
|
||||
|
||||
$this->assertSame('fake', $reloadedRelation->getTranslation(), 'The property set by the postLoad listener must get initialized on usage.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter;
|
||||
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
|
||||
abstract class AbstractTest extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function generateMessage(string $message): string
|
||||
{
|
||||
$log = $this->getLastLoggedQuery();
|
||||
|
||||
return sprintf("%s\nSQL: %s", $message, str_replace(['?'], (array) $log['params'], $log['sql']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object ...$entities
|
||||
*/
|
||||
protected function clearCachedData(...$entities): void
|
||||
{
|
||||
foreach ($entities as $entity) {
|
||||
$this->_em->refresh($entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object ...$entities
|
||||
*/
|
||||
protected function persistFlushClear(...$entities): void
|
||||
{
|
||||
foreach ($entities as $entity) {
|
||||
$this->_em->persist($entity);
|
||||
}
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter;
|
||||
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\Order;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\User;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\SQLFilter\CompanySQLFilter;
|
||||
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
|
||||
final class ChangeFiltersTest extends OrmFunctionalTestCase
|
||||
final class ChangeFiltersTest extends AbstractTest
|
||||
{
|
||||
private const COMPANY_A = 'A';
|
||||
private const COMPANY_B = 'B';
|
||||
@@ -132,11 +131,4 @@ final class ChangeFiltersTest extends OrmFunctionalTestCase
|
||||
self::assertInstanceOf(User::class, $order->user);
|
||||
self::assertEquals($companyB['userId'], $order->user->id);
|
||||
}
|
||||
|
||||
private function generateMessage(string $message): string
|
||||
{
|
||||
$log = $this->getLastLoggedQuery();
|
||||
|
||||
return sprintf("%s\nSQL: %s", $message, str_replace(['?'], (array) $log['params'], $log['sql']));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
*/
|
||||
class Insurance
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Practice::class)
|
||||
*
|
||||
* @var Practice
|
||||
*/
|
||||
public $practice;
|
||||
|
||||
public function __construct(Practice $practice, string $name)
|
||||
{
|
||||
$this->practice = $practice;
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter;
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
*/
|
||||
class Patient
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=PatientInsurance::class, mappedBy="patient", fetch="LAZY", cascade={"persist"})
|
||||
*
|
||||
* @var Collection<int, PatientInsurance>
|
||||
*/
|
||||
public $insurances;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->insurances = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<PrimaryPatInsurance>
|
||||
*/
|
||||
public function getPrimaryInsurances(): Collection
|
||||
{
|
||||
return $this->insurances->filter(static function (PatientInsurance $insurances) {
|
||||
return $insurances instanceof PrimaryPatInsurance;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<SecondaryPatInsurance>
|
||||
*/
|
||||
public function getSecondaryInsurances(): Collection
|
||||
{
|
||||
return $this->insurances->filter(static function (PatientInsurance $insurances) {
|
||||
return $insurances instanceof SecondaryPatInsurance;
|
||||
});
|
||||
}
|
||||
|
||||
public function addPrimaryInsurance(Insurance $insurance): void
|
||||
{
|
||||
$this->insurances[] = new PrimaryPatInsurance($this, $insurance);
|
||||
}
|
||||
|
||||
public function addSecondaryInsurance(Insurance $insurance): void
|
||||
{
|
||||
$this->insurances[] = new SecondaryPatInsurance($this, $insurance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
* @ORM\InheritanceType("SINGLE_TABLE")
|
||||
* @ORM\DiscriminatorMap({"primary": PrimaryPatInsurance::class, "secondary": SecondaryPatInsurance::class})
|
||||
* @ORM\DiscriminatorColumn(name="type", type="string")
|
||||
*/
|
||||
abstract class PatientInsurance
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Insurance::class, fetch="EAGER", cascade={"persist"})
|
||||
* @ORM\JoinColumn(referencedColumnName="id", nullable=false)
|
||||
*
|
||||
* @var Insurance
|
||||
*/
|
||||
public $insurance;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Patient::class, inversedBy="insurances")
|
||||
*
|
||||
* @var Patient
|
||||
*/
|
||||
public $patient;
|
||||
|
||||
public function __construct(Patient $patient, Insurance $insurance)
|
||||
{
|
||||
$this->patient = $patient;
|
||||
$this->insurance = $insurance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class Practice
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
*/
|
||||
class PrimaryPatInsurance extends PatientInsurance
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
*/
|
||||
class SecondaryPatInsurance extends PatientInsurance
|
||||
{
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter;
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter;
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\SQLFilter;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\Filter\SQLFilter;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\Order;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\User;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\SQLFilter;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\Filter\SQLFilter;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\Insurance;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
class PracticeContextSQLFilter extends SQLFilter
|
||||
{
|
||||
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias): string
|
||||
{
|
||||
if (! $this->hasParameter('practiceId') || $this->getParameter('practiceId') === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($targetEntity->getName() === Insurance::class) {
|
||||
return sprintf(
|
||||
'%s.%s = %s',
|
||||
$targetTableAlias,
|
||||
$targetEntity->associationMappings['practice']['joinColumns'][0]['name'],
|
||||
$this->getParameter('practiceId')
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter;
|
||||
|
||||
use Doctrine\ORM\Query\Filter\SQLFilter;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\Insurance;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\Patient;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\PatientInsurance;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\Practice;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\PrimaryPatInsurance;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\Entity\SecondaryPatInsurance;
|
||||
use Doctrine\Tests\ORM\Functional\Ticket\SwitchContextWithFilter\SQLFilter\PracticeContextSQLFilter;
|
||||
|
||||
final class SwitchContextTest extends AbstractTest
|
||||
{
|
||||
/**
|
||||
* @var SQLFilter|PracticeContextSQLFilter
|
||||
*/
|
||||
private $sqlFilter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->createSchemaForModels(
|
||||
Practice::class,
|
||||
Patient::class,
|
||||
PatientInsurance::class,
|
||||
PrimaryPatInsurance::class,
|
||||
SecondaryPatInsurance::class,
|
||||
Insurance::class
|
||||
);
|
||||
|
||||
$this->_em->getConfiguration()->addFilter(PracticeContextSQLFilter::class, PracticeContextSQLFilter::class);
|
||||
$this->sqlFilter = $this->_em->getFilters()->enable(PracticeContextSQLFilter::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{Patient, Patient}
|
||||
*/
|
||||
private function fixtureGenerate(): array
|
||||
{
|
||||
$practiceA = new Practice('Practice A');
|
||||
$practiceB = new Practice('Practice B');
|
||||
$insuranceAetna = new Insurance($practiceA, 'Aetna in Practice A');
|
||||
$insuranceBHumana = new Insurance($practiceB, 'Humana in Practice B');
|
||||
$insuranceBCustom = new Insurance($practiceB, 'Custom in Practice B');
|
||||
|
||||
$patientEgor = new Patient('Egor');
|
||||
$patientEgor->addPrimaryInsurance($insuranceAetna);
|
||||
$patientEgor->addPrimaryInsurance($insuranceBHumana);
|
||||
|
||||
$patientGena = new Patient('Gena');
|
||||
$patientGena->addPrimaryInsurance($insuranceBHumana);
|
||||
$patientGena->addSecondaryInsurance($insuranceBCustom);
|
||||
|
||||
$this->persistFlushClear(
|
||||
$practiceA,
|
||||
$practiceB,
|
||||
$insuranceAetna,
|
||||
$insuranceBHumana,
|
||||
$insuranceBCustom,
|
||||
$patientEgor,
|
||||
$patientGena
|
||||
);
|
||||
|
||||
return [
|
||||
$this->_em->getReference(Patient::class, $patientEgor->id),
|
||||
$this->_em->getReference(Patient::class, $patientGena->id),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable(): T $callback
|
||||
*
|
||||
* @return T
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
private function switchPracticeContext(Practice $practice, callable $callback)
|
||||
{
|
||||
$this->sqlFilter->setParameter('practiceId', $practice->id);
|
||||
|
||||
try {
|
||||
return $callback();
|
||||
} finally {
|
||||
$this->sqlFilter->setParameter('practiceId', null);
|
||||
}
|
||||
}
|
||||
|
||||
public function testSwitchContext(): void
|
||||
{
|
||||
[$patientEgor, $patentGena] = $this->fixtureGenerate();
|
||||
|
||||
$practiceA = $this->_em->getRepository(Practice::class)->findOneBy(['name' => 'Practice A']);
|
||||
$practiceB = $this->_em->getRepository(Practice::class)->findOneBy(['name' => 'Practice B']);
|
||||
|
||||
$this->switchPracticeContext($practiceA, function () use ($patientEgor, $patentGena): void {
|
||||
$this->clearCachedData($patentGena, $patientEgor);
|
||||
|
||||
self::assertCount(1, $patientEgor->insurances);
|
||||
self::assertInstanceOf(PrimaryPatInsurance::class, $patientEgor->getPrimaryInsurances()->first());
|
||||
self::assertEquals('Aetna in Practice A', $patientEgor->getPrimaryInsurances()->first()->insurance->name);
|
||||
|
||||
self::assertCount(0, $patentGena->insurances);
|
||||
});
|
||||
|
||||
$this->switchPracticeContext($practiceB, function () use ($patientEgor, $patentGena): void {
|
||||
$this->clearCachedData($patentGena, $patientEgor);
|
||||
|
||||
self::assertCount(1, $patientEgor->insurances);
|
||||
self::assertInstanceOf(PrimaryPatInsurance::class, $patientEgor->getPrimaryInsurances()->first());
|
||||
self::assertEquals('Humana in Practice B', $patientEgor->getPrimaryInsurances()->first()->insurance->name);
|
||||
|
||||
self::assertCount(2, $patentGena->insurances);
|
||||
self::assertInstanceOf(PrimaryPatInsurance::class, $patentGena->getPrimaryInsurances()->first());
|
||||
self::assertInstanceOf(SecondaryPatInsurance::class, $patentGena->getSecondaryInsurances()->first());
|
||||
self::assertEquals('Humana in Practice B', $patentGena->getPrimaryInsurances()->first()->insurance->name);
|
||||
self::assertEquals('Custom in Practice B', $patentGena->getSecondaryInsurances()->first()->insurance->name);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ class ReflectionPropertiesGetterTest extends TestCase
|
||||
|
||||
public function testPropertyGetterIsIdempotent(): void
|
||||
{
|
||||
$getter = (new ReflectionPropertiesGetter(new RuntimeReflectionService()));
|
||||
$getter = new ReflectionPropertiesGetter(new RuntimeReflectionService());
|
||||
|
||||
self::assertSame(
|
||||
$getter->getProperties(ClassWithMixedProperties::class),
|
||||
@@ -110,7 +110,7 @@ class ReflectionPropertiesGetterTest extends TestCase
|
||||
->expects(self::atLeastOnce())
|
||||
->method('getAccessibleProperty');
|
||||
|
||||
$getter = (new ReflectionPropertiesGetter($reflectionService));
|
||||
$getter = new ReflectionPropertiesGetter($reflectionService);
|
||||
|
||||
self::assertEmpty($getter->getProperties(ClassWithMixedProperties::class));
|
||||
}
|
||||
@@ -127,7 +127,7 @@ class ReflectionPropertiesGetterTest extends TestCase
|
||||
|
||||
$reflectionService->expects(self::never())->method('getAccessibleProperty');
|
||||
|
||||
$getter = (new ReflectionPropertiesGetter($reflectionService));
|
||||
$getter = new ReflectionPropertiesGetter($reflectionService);
|
||||
|
||||
self::assertEmpty($getter->getProperties(ClassWithMixedProperties::class));
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ class ORMInvalidArgumentExceptionTest extends TestCase
|
||||
. 'persist operations for entity: stdClass@' . spl_object_id($entity1)
|
||||
. '. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity '
|
||||
. 'or configure cascade persist this association in the mapping for example '
|
||||
. '@ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem '
|
||||
. '#[ORM\ManyToOne(..., cascade: [\'persist\'])]. If you cannot find out which entity causes the problem '
|
||||
. 'implement \'baz1#__toString()\' to get a clue.',
|
||||
],
|
||||
'two entities found' => [
|
||||
@@ -104,13 +104,13 @@ class ORMInvalidArgumentExceptionTest extends TestCase
|
||||
. 'cascade persist operations for entity: stdClass@' . spl_object_id($entity1) . '. '
|
||||
. 'To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity '
|
||||
. 'or configure cascade persist this association in the mapping for example '
|
||||
. '@ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem '
|
||||
. '#[ORM\ManyToOne(..., cascade: [\'persist\'])]. If you cannot find out which entity causes the problem '
|
||||
. 'implement \'baz1#__toString()\' to get a clue.' . "\n"
|
||||
. ' * A new entity was found through the relationship \'foo2#bar2\' that was not configured to '
|
||||
. 'cascade persist operations for entity: stdClass@' . spl_object_id($entity2) . '. To solve '
|
||||
. 'this issue: Either explicitly call EntityManager#persist() on this unknown entity or '
|
||||
. 'configure cascade persist this association in the mapping for example '
|
||||
. '@ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem '
|
||||
. '#[ORM\ManyToOne(..., cascade: [\'persist\'])]. If you cannot find out which entity causes the problem '
|
||||
. 'implement \'baz2#__toString()\' to get a clue.',
|
||||
],
|
||||
'two entities found, one is stringable' => [
|
||||
@@ -124,7 +124,7 @@ class ORMInvalidArgumentExceptionTest extends TestCase
|
||||
. 'persist operations for entity: ThisIsAStringRepresentationOfEntity3'
|
||||
. '. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity '
|
||||
. 'or configure cascade persist this association in the mapping for example '
|
||||
. '@ManyToOne(..,cascade={"persist"}).',
|
||||
. '#[ORM\ManyToOne(..., cascade: [\'persist\'])].',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools\Console\Command;
|
||||
|
||||
use Doctrine\ORM\Tools\Console\ApplicationCompatibility;
|
||||
use Doctrine\ORM\Tools\Console\Command\ClearCache\CollectionRegionCommand;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
use Doctrine\Tests\Models\Cache\State;
|
||||
@@ -14,6 +15,8 @@ use Symfony\Component\Console\Tester\CommandTester;
|
||||
/** @group DDC-2183 */
|
||||
class ClearCacheCollectionRegionCommandTest extends OrmFunctionalTestCase
|
||||
{
|
||||
use ApplicationCompatibility;
|
||||
|
||||
/** @var Application */
|
||||
private $application;
|
||||
|
||||
@@ -29,7 +32,7 @@ class ClearCacheCollectionRegionCommandTest extends OrmFunctionalTestCase
|
||||
$this->command = new CollectionRegionCommand(new SingleManagerProvider($this->_em));
|
||||
|
||||
$this->application = new Application();
|
||||
$this->application->add($this->command);
|
||||
self::addCommandToApplication($this->application, $this->command);
|
||||
}
|
||||
|
||||
public function testClearAllRegion(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools\Console\Command;
|
||||
|
||||
use Doctrine\ORM\Tools\Console\ApplicationCompatibility;
|
||||
use Doctrine\ORM\Tools\Console\Command\ClearCache\EntityRegionCommand;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
use Doctrine\Tests\Models\Cache\Country;
|
||||
@@ -17,6 +18,8 @@ use function trim;
|
||||
/** @group DDC-2183 */
|
||||
class ClearCacheEntityRegionCommandTest extends OrmFunctionalTestCase
|
||||
{
|
||||
use ApplicationCompatibility;
|
||||
|
||||
/** @var Application */
|
||||
private $application;
|
||||
|
||||
@@ -32,7 +35,7 @@ class ClearCacheEntityRegionCommandTest extends OrmFunctionalTestCase
|
||||
$this->command = new EntityRegionCommand(new SingleManagerProvider($this->_em));
|
||||
|
||||
$this->application = new Application();
|
||||
$this->application->add($this->command);
|
||||
self::addCommandToApplication($this->application, $this->command);
|
||||
}
|
||||
|
||||
public function testClearAllRegion(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools\Console\Command;
|
||||
|
||||
use Doctrine\ORM\Tools\Console\ApplicationCompatibility;
|
||||
use Doctrine\ORM\Tools\Console\Command\ClearCache\QueryRegionCommand;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
@@ -13,6 +14,8 @@ use Symfony\Component\Console\Tester\CommandTester;
|
||||
/** @group DDC-2183 */
|
||||
class ClearCacheQueryRegionCommandTest extends OrmFunctionalTestCase
|
||||
{
|
||||
use ApplicationCompatibility;
|
||||
|
||||
/** @var Application */
|
||||
private $application;
|
||||
|
||||
@@ -28,7 +31,7 @@ class ClearCacheQueryRegionCommandTest extends OrmFunctionalTestCase
|
||||
$this->command = new QueryRegionCommand(new SingleManagerProvider($this->_em));
|
||||
|
||||
$this->application = new Application();
|
||||
$this->application->add($this->command);
|
||||
self::addCommandToApplication($this->application, $this->command);
|
||||
}
|
||||
|
||||
public function testClearAllRegion(): void
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Doctrine\Tests\ORM\Tools\Console\Command;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\ORM\Configuration;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Tools\Console\ApplicationCompatibility;
|
||||
use Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
use Doctrine\Tests\DoctrineTestCase;
|
||||
@@ -18,6 +19,8 @@ use function array_merge;
|
||||
|
||||
class EnsureProductionSettingsCommandTest extends DoctrineTestCase
|
||||
{
|
||||
use ApplicationCompatibility;
|
||||
|
||||
public function testExecute(): void
|
||||
{
|
||||
$em = $this->createMock(EntityManagerInterface::class);
|
||||
@@ -103,7 +106,7 @@ class EnsureProductionSettingsCommandTest extends DoctrineTestCase
|
||||
array $input = []
|
||||
): int {
|
||||
$application = new Application();
|
||||
$application->add(new EnsureProductionSettingsCommand(new SingleManagerProvider($em)));
|
||||
self::addCommandToApplication($application, new EnsureProductionSettingsCommand(new SingleManagerProvider($em)));
|
||||
|
||||
$command = $application->find('orm:ensure-production-settings');
|
||||
$tester = new CommandTester($command);
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Doctrine\Tests\ORM\Tools\Console\Command;
|
||||
use Doctrine\ORM\Configuration;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Tools\Console\ApplicationCompatibility;
|
||||
use Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
|
||||
@@ -35,6 +36,8 @@ use const DIRECTORY_SEPARATOR;
|
||||
|
||||
class GenerateRepositoriesCommandTest extends OrmFunctionalTestCase
|
||||
{
|
||||
use ApplicationCompatibility;
|
||||
|
||||
/** @var Application */
|
||||
private $application;
|
||||
|
||||
@@ -53,7 +56,7 @@ class GenerateRepositoriesCommandTest extends OrmFunctionalTestCase
|
||||
$metadataDriver->addPaths([__DIR__ . '/../../../../Models/DDC3231/']);
|
||||
|
||||
$this->application = new Application();
|
||||
$this->application->add(new GenerateRepositoriesCommand(new SingleManagerProvider($this->_em)));
|
||||
self::addCommandToApplication($this->application, new GenerateRepositoriesCommand(new SingleManagerProvider($this->_em)));
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
@@ -163,7 +166,7 @@ class GenerateRepositoriesCommandTest extends OrmFunctionalTestCase
|
||||
|
||||
$application = new Application();
|
||||
$application->setHelperSet(new HelperSet(['em' => new EntityManagerHelper($em)]));
|
||||
$application->add(new GenerateRepositoriesCommand());
|
||||
self::addCommandToApplication($application, new GenerateRepositoriesCommand());
|
||||
|
||||
$command = $application->find('orm:generate-repositories');
|
||||
$tester = new CommandTester($command);
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Doctrine\Tests\ORM\Tools\Console\Command;
|
||||
use Doctrine\ORM\Configuration;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\ORM\Tools\Console\ApplicationCompatibility;
|
||||
use Doctrine\ORM\Tools\Console\Command\InfoCommand;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
|
||||
@@ -20,6 +21,8 @@ use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class InfoCommandTest extends OrmFunctionalTestCase
|
||||
{
|
||||
use ApplicationCompatibility;
|
||||
|
||||
/** @var Application */
|
||||
private $application;
|
||||
|
||||
@@ -35,7 +38,7 @@ class InfoCommandTest extends OrmFunctionalTestCase
|
||||
|
||||
$this->application = new Application();
|
||||
|
||||
$this->application->add(new InfoCommand(new SingleManagerProvider($this->_em)));
|
||||
self::addCommandToApplication($this->application, new InfoCommand(new SingleManagerProvider($this->_em)));
|
||||
|
||||
$this->command = $this->application->find('orm:info');
|
||||
$this->tester = new CommandTester($this->command);
|
||||
@@ -66,7 +69,7 @@ class InfoCommandTest extends OrmFunctionalTestCase
|
||||
|
||||
$application = new Application();
|
||||
$application->setHelperSet(new HelperSet(['em' => new EntityManagerHelper($em)]));
|
||||
$application->add(new InfoCommand());
|
||||
self::addCommandToApplication($application, new InfoCommand());
|
||||
|
||||
$command = $application->find('orm:info');
|
||||
$tester = new CommandTester($command);
|
||||
@@ -105,7 +108,7 @@ class InfoCommandTest extends OrmFunctionalTestCase
|
||||
|
||||
$application = new Application();
|
||||
$application->setHelperSet(new HelperSet(['em' => new EntityManagerHelper($em)]));
|
||||
$application->add(new InfoCommand());
|
||||
self::addCommandToApplication($application, new InfoCommand());
|
||||
|
||||
$command = $application->find('orm:info');
|
||||
$tester = new CommandTester($command);
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools\Console\Command;
|
||||
|
||||
use Doctrine\ORM\Tools\Console\ApplicationCompatibility;
|
||||
use Doctrine\ORM\Tools\Console\Command\MappingDescribeCommand;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
use Doctrine\Tests\Models\Cache\AttractionInfo;
|
||||
@@ -18,6 +19,8 @@ use Symfony\Component\Console\Tester\CommandTester;
|
||||
*/
|
||||
class MappingDescribeCommandTest extends OrmFunctionalTestCase
|
||||
{
|
||||
use ApplicationCompatibility;
|
||||
|
||||
/** @var Application */
|
||||
private $application;
|
||||
|
||||
@@ -32,7 +35,7 @@ class MappingDescribeCommandTest extends OrmFunctionalTestCase
|
||||
parent::setUp();
|
||||
|
||||
$this->application = new Application();
|
||||
$this->application->add(new MappingDescribeCommand(new SingleManagerProvider($this->_em)));
|
||||
self::addCommandToApplication($this->application, new MappingDescribeCommand(new SingleManagerProvider($this->_em)));
|
||||
|
||||
$this->command = $this->application->find('orm:mapping:describe');
|
||||
$this->tester = new CommandTester($this->command);
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools\Console\Command;
|
||||
|
||||
use Doctrine\ORM\Tools\Console\ApplicationCompatibility;
|
||||
use Doctrine\ORM\Tools\Console\Command\RunDqlCommand;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
use Doctrine\Tests\Models\Generic\DateTimeModel;
|
||||
@@ -20,6 +21,8 @@ use function trim;
|
||||
*/
|
||||
class RunDqlCommandTest extends OrmFunctionalTestCase
|
||||
{
|
||||
use ApplicationCompatibility;
|
||||
|
||||
/** @var Application */
|
||||
private $application;
|
||||
|
||||
@@ -38,7 +41,7 @@ class RunDqlCommandTest extends OrmFunctionalTestCase
|
||||
$this->command = new RunDqlCommand(new SingleManagerProvider($this->_em));
|
||||
|
||||
$this->application = new Application();
|
||||
$this->application->add($this->command);
|
||||
self::addCommandToApplication($this->application, $this->command);
|
||||
|
||||
$this->tester = new CommandTester($this->command);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace Doctrine\Tests\ORM\Tools\Console\Command;
|
||||
|
||||
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
||||
use Doctrine\ORM\Tools\Console\ApplicationCompatibility;
|
||||
use Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
@@ -19,6 +20,8 @@ use Symfony\Component\Console\Tester\CommandTester;
|
||||
*/
|
||||
class ValidateSchemaCommandTest extends OrmFunctionalTestCase
|
||||
{
|
||||
use ApplicationCompatibility;
|
||||
|
||||
/** @var ValidateSchemaCommand */
|
||||
private $command;
|
||||
|
||||
@@ -34,7 +37,7 @@ class ValidateSchemaCommandTest extends OrmFunctionalTestCase
|
||||
}
|
||||
|
||||
$application = new Application();
|
||||
$application->add(new ValidateSchemaCommand(new SingleManagerProvider($this->_em)));
|
||||
self::addCommandToApplication($application, new ValidateSchemaCommand(new SingleManagerProvider($this->_em)));
|
||||
|
||||
$this->command = $application->find('orm:validate-schema');
|
||||
$this->tester = new CommandTester($this->command);
|
||||
|
||||
@@ -46,6 +46,24 @@ final class LimitSubqueryOutputWalkerTest extends PaginationTestCase
|
||||
$this->entityManager->getConnection()->setDatabasePlatform($platform);
|
||||
}
|
||||
|
||||
public function testSubqueryClonedCompletely(): void
|
||||
{
|
||||
$query = $this->createQuery('SELECT p FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p');
|
||||
$query->setParameter('dummy-param', 123);
|
||||
$query->setHint('dummy-hint', 'dummy-value');
|
||||
$query->setCacheable(true);
|
||||
|
||||
$walker = new LimitSubqueryOutputWalker($query, new Query\ParserResult(), []);
|
||||
|
||||
self::assertNotSame($query, $walker->getQuery());
|
||||
self::assertTrue($walker->getQuery()->hasHint('dummy-hint'));
|
||||
self::assertSame('dummy-value', $walker->getQuery()->getHint('dummy-hint'));
|
||||
self::assertNotSame($query->getParameters(), $walker->getQuery()->getParameters());
|
||||
self::assertInstanceOf(Query\Parameter::class, $param = $walker->getQuery()->getParameter('dummy-param'));
|
||||
self::assertSame(123, $param->getValue());
|
||||
self::assertFalse($walker->getQuery()->isCacheable());
|
||||
}
|
||||
|
||||
public function testLimitSubquery(): void
|
||||
{
|
||||
$query = $this->createQuery('SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a');
|
||||
|
||||
@@ -679,8 +679,6 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $classNames
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function setUpEntitySchema(array $classNames): void
|
||||
|
||||
Reference in New Issue
Block a user