mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bff0919a7 | ||
|
|
9ef0f5301b | ||
|
|
4989ca6f15 | ||
|
|
32d1e97ce7 | ||
|
|
ca8147b148 | ||
|
|
c8ebea77f0 | ||
|
|
23f22860f1 | ||
|
|
b24586b1b5 | ||
|
|
fe5ee705db | ||
|
|
0511a9f790 | ||
|
|
0e3d5e8c82 | ||
|
|
72ffb3bfbf | ||
|
|
2e9a1adc23 | ||
|
|
59938cae57 | ||
|
|
298dc9bb6a | ||
|
|
da67f323e0 | ||
|
|
63635cad0e | ||
|
|
a0d401b688 | ||
|
|
6acbadfbbe | ||
|
|
c64dcb4d38 | ||
|
|
3304290b21 | ||
|
|
1865717721 | ||
|
|
828b06e20f | ||
|
|
c2b844d2e3 | ||
|
|
b45d5329f8 | ||
|
|
c1047b30e3 | ||
|
|
aa62efa30a | ||
|
|
f71956f001 | ||
|
|
96f9b29573 | ||
|
|
9a55cf4f30 | ||
|
|
9d680a6de4 | ||
|
|
7a59281157 | ||
|
|
5def068fe9 | ||
|
|
693acbf812 | ||
|
|
c1ce2bb687 | ||
|
|
5f6896a2f9 | ||
|
|
930a790a5a | ||
|
|
3b7de17f2e | ||
|
|
8afaa63d73 | ||
|
|
2ad720b304 | ||
|
|
a939dc2e0d | ||
|
|
f8186b1203 | ||
|
|
048e308241 | ||
|
|
4274dac8a2 | ||
|
|
c1af765960 | ||
|
|
5f3551852f | ||
|
|
8144cad07c | ||
|
|
70fd68cf7f | ||
|
|
437259556c | ||
|
|
e7e2fef56c | ||
|
|
3e34b8e86a | ||
|
|
7d950aba62 | ||
|
|
8fe1200edf | ||
|
|
397358c308 | ||
|
|
ac37a87a3d | ||
|
|
613f52db5a | ||
|
|
cf5503b0d8 | ||
|
|
ae5e9c8c6c | ||
|
|
1a2826d147 | ||
|
|
05760f9454 | ||
|
|
26af013842 | ||
|
|
d68c1dcd6d | ||
|
|
9bf407f336 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -11,7 +11,6 @@ build.properties.dev export-ignore
|
||||
build.xml export-ignore
|
||||
CONTRIBUTING.md export-ignore
|
||||
phpunit.xml.dist export-ignore
|
||||
run-all.sh export-ignore
|
||||
phpcs.xml.dist export-ignore
|
||||
phpbench.json export-ignore
|
||||
phpstan.neon export-ignore
|
||||
|
||||
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.3.0"
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@v12.2.0"
|
||||
|
||||
20
.github/workflows/composer-lint.yml
vendored
Normal file
20
.github/workflows/composer-lint.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: "Composer Lint"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- ".github/workflows/composer-lint.yml"
|
||||
- "composer.json"
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- ".github/workflows/composer-lint.yml"
|
||||
- "composer.json"
|
||||
|
||||
jobs:
|
||||
composer-lint:
|
||||
name: "Composer Lint"
|
||||
uses: "doctrine/.github/.github/workflows/composer-lint.yml@v12.2.0"
|
||||
26
.github/workflows/continuous-integration.yml
vendored
26
.github/workflows/continuous-integration.yml
vendored
@@ -41,6 +41,7 @@ jobs:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
- "8.5"
|
||||
dbal-version:
|
||||
- "default"
|
||||
extension:
|
||||
@@ -64,7 +65,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -98,7 +99,7 @@ jobs:
|
||||
ORM_PROXY_IMPLEMENTATION: "${{ matrix.proxy }}"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
uses: "actions/upload-artifact@v5"
|
||||
with:
|
||||
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.proxy }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
@@ -115,6 +116,7 @@ jobs:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
- "8.5"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -147,7 +149,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -172,7 +174,7 @@ jobs:
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
uses: "actions/upload-artifact@v5"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.extension }}-coverage"
|
||||
path: "coverage.xml"
|
||||
@@ -189,6 +191,7 @@ jobs:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
- "8.5"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -218,7 +221,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -243,7 +246,7 @@ jobs:
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
uses: "actions/upload-artifact@v5"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage.xml"
|
||||
@@ -260,6 +263,7 @@ jobs:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
- "8.5"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -289,7 +293,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -321,7 +325,7 @@ jobs:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 1
|
||||
|
||||
- name: "Upload coverage files"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
uses: "actions/upload-artifact@v5"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
@@ -341,7 +345,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -373,12 +377,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: "Download coverage files"
|
||||
uses: "actions/download-artifact@v4"
|
||||
uses: "actions/download-artifact@v6"
|
||||
with:
|
||||
path: "reports"
|
||||
|
||||
|
||||
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.3.0"
|
||||
uses: "doctrine/.github/.github/workflows/documentation.yml@v12.2.0"
|
||||
|
||||
2
.github/workflows/phpbench.yml
vendored
2
.github/workflows/phpbench.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.3.0"
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@v12.2.0"
|
||||
secrets:
|
||||
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
|
||||
2
.github/workflows/static-analysis.yml
vendored
2
.github/workflows/static-analysis.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v5"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
|
||||
@@ -1,29 +1,39 @@
|
||||
{
|
||||
"name": "doctrine/orm",
|
||||
"type": "library",
|
||||
"description": "Object-Relational-Mapper for PHP",
|
||||
"keywords": ["orm", "database"],
|
||||
"homepage": "https://www.doctrine-project.org/projects/orm.html",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
|
||||
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
|
||||
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
|
||||
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
|
||||
{"name": "Marco Pivetta", "email": "ocramius@gmail.com"}
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"orm",
|
||||
"database"
|
||||
],
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com"
|
||||
}
|
||||
],
|
||||
"homepage": "https://www.doctrine-project.org/projects/orm.html",
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0",
|
||||
"composer-runtime-api": "^2",
|
||||
"ext-ctype": "*",
|
||||
"composer-runtime-api": "^2",
|
||||
"doctrine/cache": "^1.12.1 || ^2.1.1",
|
||||
"doctrine/collections": "^1.5 || ^2.1",
|
||||
"doctrine/common": "^3.0.3",
|
||||
@@ -41,14 +51,13 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "^1.13 || ^2",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^13.0",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^14.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": "~1.4.10 || 2.1.23",
|
||||
"phpstan/phpstan-deprecation-rules": "^1 || ^2",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"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"
|
||||
@@ -62,17 +71,29 @@
|
||||
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Doctrine\\ORM\\": "src" }
|
||||
"psr-4": {
|
||||
"Doctrine\\ORM\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Tests\\": "tests/Tests",
|
||||
"Doctrine\\Performance\\": "tests/Performance",
|
||||
"Doctrine\\StaticAnalysis\\": "tests/StaticAnalysis",
|
||||
"Doctrine\\Performance\\": "tests/Performance"
|
||||
"Doctrine\\Tests\\": "tests/Tests"
|
||||
}
|
||||
},
|
||||
"bin": ["bin/doctrine"],
|
||||
"archive": {
|
||||
"exclude": ["!vendor", "tests", "*phpunit.xml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp"]
|
||||
"bin": [
|
||||
"bin/doctrine"
|
||||
],
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"docs": "composer --working-dir docs update && ./docs/vendor/bin/build-docs.sh @additional_args"
|
||||
}
|
||||
}
|
||||
|
||||
2
docs/.gitignore
vendored
2
docs/.gitignore
vendored
@@ -1,3 +1,3 @@
|
||||
composer.lock
|
||||
vendor/
|
||||
build/
|
||||
output/
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# 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."
|
||||
@@ -4,19 +4,15 @@ The documentation is written in [ReStructured Text](https://docutils.sourceforge
|
||||
|
||||
## How to Generate:
|
||||
|
||||
In the `docs/` folder, run
|
||||
In the project root, run
|
||||
|
||||
composer update
|
||||
composer docs
|
||||
|
||||
Then compile the documentation with:
|
||||
|
||||
make html
|
||||
|
||||
This will generate the documentation into the `build` subdirectory.
|
||||
This will generate the documentation into the `docs/output` subdirectory.
|
||||
|
||||
To browse the documentation, you need to run a webserver:
|
||||
|
||||
cd build/html
|
||||
cd docs/output
|
||||
php -S localhost:8000
|
||||
|
||||
Now the documentation is available at [http://localhost:8000](http://localhost:8000).
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
"description": "Documentation for the Object-Relational Mapper\"",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"phpdocumentor/guides-cli": "1.7.1",
|
||||
"phpdocumentor/filesystem": "1.7.1"
|
||||
"require-dev": {
|
||||
"doctrine/docs-builder": "^1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,8 +101,16 @@ The ``Paginate::count(Query $query)`` looks like:
|
||||
{
|
||||
static public function count(Query $query)
|
||||
{
|
||||
/** @var Query $countQuery */
|
||||
$countQuery = clone $query;
|
||||
/*
|
||||
To avoid changing the $query passed into the method and to make sure a possibly existing
|
||||
ResultSetMapping is discarded, we create a new query object any copy relevant data over.
|
||||
*/
|
||||
$countQuery = new Query($query->getEntityManager());
|
||||
$countQuery->setDQL($query->getDQL());
|
||||
$countQuery->setParameters(clone $query->getParameters());
|
||||
foreach ($query->getHints() as $name => $value) {
|
||||
$countQuery->setHint($name, $value);
|
||||
}
|
||||
|
||||
$countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('DoctrineExtensions\Paginate\CountSqlWalker'));
|
||||
$countQuery->setFirstResult(null)->setMaxResults(null);
|
||||
@@ -111,7 +119,7 @@ The ``Paginate::count(Query $query)`` looks like:
|
||||
}
|
||||
}
|
||||
|
||||
It clones the query, resets the limit clause first and max results
|
||||
This resets the limit clause first and max results
|
||||
and registers the ``CountSqlWalker`` custom tree walker which
|
||||
will modify the AST to execute a count query. The walkers
|
||||
implementation is:
|
||||
|
||||
@@ -13,7 +13,6 @@ If this documentation is not helping to answer questions you have about
|
||||
Doctrine ORM don't panic. You can get help from different sources:
|
||||
|
||||
- There is a :doc:`FAQ <reference/faq>` with answers to frequent questions.
|
||||
- The `Doctrine Mailing List <https://groups.google.com/group/doctrine-user>`_
|
||||
- Slack chat room `#orm <https://www.doctrine-project.org/slack>`_
|
||||
- Report a bug on `GitHub <https://github.com/doctrine/orm/issues>`_.
|
||||
- On `StackOverflow <https://stackoverflow.com/questions/tagged/doctrine-orm>`_
|
||||
|
||||
@@ -279,7 +279,7 @@ requests.
|
||||
Connection
|
||||
----------
|
||||
|
||||
The ``$connection`` passed as the first argument to he constructor of
|
||||
The ``$connection`` passed as the first argument to the constructor of
|
||||
``EntityManager`` has to be an instance of ``Doctrine\DBAL\Connection``.
|
||||
You can use the factory ``Doctrine\DBAL\DriverManager::getConnection()``
|
||||
to create such a connection. The DBAL configuration is explained in the
|
||||
|
||||
@@ -168,7 +168,7 @@ recommended, at least not as long as an entity instance still holds
|
||||
references to proxy objects or is still managed by an EntityManager.
|
||||
By default, serializing proxy objects does not initialize them. On
|
||||
unserialization, resulting objects are detached from the entity
|
||||
manager and cannot be initialiazed anymore. You can implement the
|
||||
manager and cannot be initialized anymore. You can implement the
|
||||
``__serialize()`` method if you want to change that behavior, but
|
||||
then you need to ensure that you won't generate large serialized
|
||||
object graphs and take care of circular associations.
|
||||
|
||||
@@ -30,7 +30,7 @@ table alias of the SQL table of the entity.
|
||||
|
||||
For the filter to correctly function, the following rules must be followed. Failure to do so will lead to unexpected results from the query cache.
|
||||
1. Parameters for the query should be set on the filter object by ``SQLFilter#setParameter()`` before the filter is used by the ORM ( i.e. do not set parameters inside ``SQLFilter#addFilterConstraint()`` function ).
|
||||
2. The filter must be deterministic. Don't change the values base on external inputs.
|
||||
2. The filter must be deterministic. Don't change the values based on external inputs.
|
||||
|
||||
The ``SQLFilter#getParameter()`` function takes care of the proper quoting of parameters.
|
||||
|
||||
|
||||
@@ -187,6 +187,14 @@ internally by the ORM currently refers to fields by their name only, without tak
|
||||
class containing the field into consideration. This makes it impossible to keep separate
|
||||
mapping configuration for both fields.
|
||||
|
||||
Apart from that, in the case of having multiple ``private`` fields of the same name within
|
||||
the class hierarchy an entity or mapped superclass, the Collection filtering API cannot determine
|
||||
the right field to look at. Even if only one of these fields is actually mapped, the ``ArrayCollection``
|
||||
will not be able to tell, since it does not have access to any metadata.
|
||||
|
||||
Thus, to avoid problems in this regard, it is best to avoid having multiple ``private`` fields of the
|
||||
same name in class hierarchies containing entity and mapped superclasses.
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ Something like below for an entity region:
|
||||
|
||||
|
||||
If the entity holds a collection that also needs to be cached.
|
||||
An collection region could look something like:
|
||||
A collection region could look something like:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -630,7 +630,7 @@ DELETE / UPDATE queries
|
||||
DQL UPDATE / DELETE statements are ported directly into a database and bypass
|
||||
the second-level cache.
|
||||
Entities that are already cached will NOT be invalidated.
|
||||
However the cached data could be evicted using the cache API or an special query hint.
|
||||
However the cached data could be evicted using the cache API or a special query hint.
|
||||
|
||||
|
||||
Execute the ``UPDATE`` and invalidate ``all cache entries`` using ``Query::HINT_CACHE_EVICT``
|
||||
|
||||
@@ -118,7 +118,7 @@ entity might look like this:
|
||||
}
|
||||
}
|
||||
|
||||
Now the possiblity of mass-assignment exists on this entity and can
|
||||
Now the possibility of mass-assignment exists on this entity and can
|
||||
be exploited by attackers to set the "isAdmin" flag to true on any
|
||||
object when you pass the whole request data to this method like:
|
||||
|
||||
|
||||
@@ -234,6 +234,7 @@
|
||||
<!-- extending a class from another package -->
|
||||
<exclude-pattern>tests/Tests/Mocks/DatabasePlatformMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Mocks/SchemaManagerMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/AbstractQueryTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC3634Test.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
|
||||
@@ -18,18 +18,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/AbstractQuery.php
|
||||
|
||||
-
|
||||
message: '#^Expression "\$setCacheEntry\(\$data\)" on a separate line does not do anything\.$#'
|
||||
identifier: expr.resultUnused
|
||||
count: 1
|
||||
path: src/AbstractQuery.php
|
||||
|
||||
-
|
||||
message: '#^Expression "\$setCacheEntry\(\$stmt\)" on a separate line does not do anything\.$#'
|
||||
identifier: expr.resultUnused
|
||||
count: 1
|
||||
path: src/AbstractQuery.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\AbstractQuery\:\:getParameter\(\) should return Doctrine\\ORM\\Query\\Parameter\|null but returns Doctrine\\ORM\\Query\\Parameter\|false\|null\.$#'
|
||||
identifier: return.type
|
||||
@@ -102,6 +90,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Cache/CollectionHydrator.php
|
||||
|
||||
-
|
||||
message: '#^If condition is always false\.$#'
|
||||
identifier: if.alwaysFalse
|
||||
count: 1
|
||||
path: src/Cache/DefaultCache.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Cache\\DefaultCache\:\:buildCollectionCacheKey\(\) has parameter \$metadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -264,12 +258,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Cache/DefaultQueryCache.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$result of class Doctrine\\ORM\\Cache\\QueryCacheEntry constructor expects array\<string, mixed\>, array\<int\|string, array\<string, array\<mixed\>\>\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Cache/DefaultQueryCache.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$key of method Doctrine\\ORM\\Cache\\Logging\\CacheLogger\:\:entityCacheHit\(\) expects Doctrine\\ORM\\Cache\\EntityCacheKey, Doctrine\\ORM\\Cache\\CacheKey given\.$#'
|
||||
identifier: argument.type
|
||||
@@ -546,12 +534,6 @@ parameters:
|
||||
count: 5
|
||||
path: src/Cache/Persister/Entity/AbstractEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Cache\\Persister\\Entity\\AbstractEntityPersister\:\:loadAll\(\) has no return type specified\.$#'
|
||||
identifier: missingType.return
|
||||
count: 1
|
||||
path: src/Cache/Persister/Entity/AbstractEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Cache\\Persister\\Entity\\AbstractEntityPersister\:\:loadManyToManyCollection\(\) has parameter \$assoc with no value type specified in iterable type array\.$#'
|
||||
identifier: missingType.iterableValue
|
||||
@@ -630,6 +612,18 @@ parameters:
|
||||
count: 1
|
||||
path: src/Cache/TimestampQueryCacheValidator.php
|
||||
|
||||
-
|
||||
message: '#^Call to function is_a\(\) with arguments class\-string\<Doctrine\\ORM\\EntityRepository\>, ''Doctrine\\\\ORM\\\\EntityRepository'' and true will always evaluate to true\.$#'
|
||||
identifier: function.alreadyNarrowedType
|
||||
count: 1
|
||||
path: src/Configuration.php
|
||||
|
||||
-
|
||||
message: '#^Call to function is_a\(\) with arguments class\-string\<Doctrine\\ORM\\EntityRepository\>, ''Doctrine\\\\Persistence\\\\ObjectRepository'' and true will always evaluate to true\.$#'
|
||||
identifier: function.alreadyNarrowedType
|
||||
count: 1
|
||||
path: src/Configuration.php
|
||||
|
||||
-
|
||||
message: '#^Call to function method_exists\(\) with ''Doctrine\\\\DBAL\\\\Configuration'' and ''getResultCache'' will always evaluate to true\.$#'
|
||||
identifier: function.alreadyNarrowedType
|
||||
@@ -852,6 +846,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/EntityManager.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\EntityRepository\:\:findBy\(\) should return list\<T of object\> but returns array\<mixed\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/EntityRepository.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\EntityRepository\:\:findOneBy\(\) should return \(T of object\)\|null but returns object\|null\.$#'
|
||||
identifier: return.type
|
||||
@@ -973,13 +973,13 @@ parameters:
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
|
||||
-
|
||||
message: '#^Parameter &\$id by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, string\>, array\<int\|string, string\> given\.$#'
|
||||
message: '#^Parameter &\$id by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, string\>, array\<string\> given\.$#'
|
||||
identifier: parameterByRef.type
|
||||
count: 1
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
|
||||
-
|
||||
message: '#^Parameter &\$nonemptyComponents by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, bool\>, array\<int\|string, bool\> given\.$#'
|
||||
message: '#^Parameter &\$nonemptyComponents by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, bool\>, array\<bool\> given\.$#'
|
||||
identifier: parameterByRef.type
|
||||
count: 1
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
@@ -1056,6 +1056,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Internal/HydrationCompleteHandler.php
|
||||
|
||||
-
|
||||
message: '#^Offset int\|null might not exist on array\<int, object\>\.$#'
|
||||
identifier: offsetAccess.notFound
|
||||
count: 1
|
||||
path: src/Internal/StronglyConnectedComponents.php
|
||||
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Internal\\StronglyConnectedComponents\:\:\$representingNodes \(array\<int, object\>\) does not accept array\<int\|string, object\>\.$#'
|
||||
identifier: assign.propertyType
|
||||
@@ -1188,6 +1194,12 @@ parameters:
|
||||
count: 5
|
||||
path: src/Mapping/ClassMetadata.php
|
||||
|
||||
-
|
||||
message: '#^Call to function is_a\(\) with Doctrine\\DBAL\\Platforms\\OraclePlatform and ''Doctrine\\\\DBAL…'' will always evaluate to false\.$#'
|
||||
identifier: function.impossibleType
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
-
|
||||
message: '#^If condition is always true\.$#'
|
||||
identifier: if.alwaysTrue
|
||||
@@ -1669,7 +1681,7 @@ parameters:
|
||||
path: src/Mapping/ClassMetadataInfo.php
|
||||
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadataInfo\<T of object\>\:\:\$embeddedClasses \(array\<string, array\{class\: class\-string, columnPrefix\: string\|null, declaredField\: string\|null, originalField\: string\|null, inherited\?\: class\-string, declared\?\: class\-string\}\>\) does not accept non\-empty\-array\<int\|string, array\{class\: string, columnPrefix\: mixed, declaredField\: mixed, originalField\: mixed, inherited\?\: class\-string, declared\?\: class\-string\}\>\.$#'
|
||||
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadataInfo\<T of object\>\:\:\$embeddedClasses \(array\<string, array\{class\: class\-string, columnPrefix\: string\|null, declaredField\: string\|null, originalField\: string\|null, inherited\?\: class\-string, declared\?\: class\-string\}\>\) does not accept non\-empty\-array\<array\{class\: string, columnPrefix\: mixed, declaredField\: mixed, originalField\: mixed, inherited\?\: class\-string, declared\?\: class\-string\}\>\.$#'
|
||||
identifier: assign.propertyType
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadataInfo.php
|
||||
@@ -1681,19 +1693,7 @@ parameters:
|
||||
path: src/Mapping/ClassMetadataInfo.php
|
||||
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadataInfo\<T of object\>\:\:\$namedNativeQueries \(array\<string, array\<string, mixed\>\>\) does not accept array\<int\|string, array\<string, mixed\>\>\.$#'
|
||||
identifier: assign.propertyType
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadataInfo.php
|
||||
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadataInfo\<T of object\>\:\:\$namedQueries \(array\<string, array\<string, mixed\>\>\) does not accept array\<int\|string, array\<string, mixed\>\>\.$#'
|
||||
identifier: assign.propertyType
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadataInfo.php
|
||||
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadataInfo\<T of object\>\:\:\$sqlResultSetMappings \(array\<string, array\{name\: string, entities\: array\<mixed\>, columns\: array\<mixed\>\}\>\) does not accept non\-empty\-array\<int\|string, array\<string, mixed\>\>\.$#'
|
||||
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadataInfo\<T of object\>\:\:\$sqlResultSetMappings \(array\<string, array\{name\: string, entities\: array\<mixed\>, columns\: array\<mixed\>\}\>\) does not accept non\-empty\-array\<non\-empty\-array\<string, mixed\>\>\.$#'
|
||||
identifier: assign.propertyType
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadataInfo.php
|
||||
@@ -1722,6 +1722,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadataInfo.php
|
||||
|
||||
-
|
||||
message: '#^Template type T is declared as covariant, but occurs in invariant position in return type of method Doctrine\\ORM\\Mapping\\ClassMetadataInfo\:\:getReflectionClass\(\)\.$#'
|
||||
identifier: generics.variance
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadataInfo.php
|
||||
|
||||
-
|
||||
message: '#^@readonly property cannot have a default value\.$#'
|
||||
identifier: property.readOnlyByPhpDocDefaultValue
|
||||
@@ -2742,18 +2748,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:expandCriteriaParameters\(\) should return array\{list\<mixed\>, list\<int\|string\|null\>\} but returns array\{array\<mixed\>, list\<int\|string\|null\>\}\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:expandParameters\(\) should return array\{list\<mixed\>, list\<int\|string\|null\>\} but returns array\{array\<mixed\>, list\<int\|string\|null\>\}\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:expandToManyParameters\(\) return type has no value type specified in iterable type array\.$#'
|
||||
identifier: missingType.iterableValue
|
||||
@@ -2790,12 +2784,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getIndividualValue\(\) should return list\<mixed\> but returns array\<mixed\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getManyToManyCollection\(\) has parameter \$assoc with no value type specified in iterable type array\.$#'
|
||||
identifier: missingType.iterableValue
|
||||
@@ -2856,24 +2844,12 @@ parameters:
|
||||
count: 5
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getTypes\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:load\(\) has parameter \$assoc with no value type specified in iterable type array\.$#'
|
||||
identifier: missingType.iterableValue
|
||||
count: 5
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:loadAll\(\) has no return type specified\.$#'
|
||||
identifier: missingType.return
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:loadCollectionFromStatement\(\) has parameter \$coll with generic class Doctrine\\ORM\\PersistentCollection but does not specify its types\: TKey, T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -2922,18 +2898,6 @@ parameters:
|
||||
count: 8
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Offset ''relationToTargetKeyColumns'' might not exist on array\{cache\?\: array, cascade\: array\<string\>, declared\?\: class\-string, fetch\: mixed, fieldName\: string, id\?\: bool, inherited\?\: class\-string, indexBy\?\: string, \.\.\.\}\.$#'
|
||||
identifier: offsetAccess.notFound
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Offset ''sourceToTargetKeyColumns'' might not exist on array\{cache\?\: array, cascade\: array\<string\>, declared\?\: class\-string, fetch\: mixed, fieldName\: string, id\?\: bool, inherited\?\: class\-string, indexBy\?\: string, \.\.\.\}\.$#'
|
||||
identifier: offsetAccess.notFound
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Offset ''targetToSourceKeyColumns'' might not exist on array\{cache\?\: array, cascade\: array\<string\>, declared\?\: class\-string, fetch\: mixed, fieldName\: string, id\?\: bool, inherited\?\: class\-string, indexBy\?\: string, \.\.\.\}\.$#'
|
||||
identifier: offsetAccess.notFound
|
||||
@@ -2988,12 +2952,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Strict comparison using \=\=\= between string and null will always evaluate to false\.$#'
|
||||
identifier: identical.alwaysFalse
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\CachedPersisterContext\:\:__construct\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -3048,12 +3006,6 @@ parameters:
|
||||
count: 5
|
||||
path: src/Persisters/Entity/EntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\EntityPersister\:\:loadAll\(\) has no return type specified\.$#'
|
||||
identifier: missingType.return
|
||||
count: 1
|
||||
path: src/Persisters/Entity/EntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\EntityPersister\:\:loadManyToManyCollection\(\) has parameter \$assoc with no value type specified in iterable type array\.$#'
|
||||
identifier: missingType.iterableValue
|
||||
@@ -3195,33 +3147,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '''
|
||||
#^Call to method __construct\(\) of deprecated class Doctrine\\Common\\Proxy\\AbstractProxyFactory\:
|
||||
The AbstractProxyFactory class is deprecated since doctrine/common 3\.5\.$#
|
||||
'''
|
||||
identifier: staticMethod.deprecatedClass
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '''
|
||||
#^Call to method generateProxyClasses\(\) of deprecated class Doctrine\\Common\\Proxy\\AbstractProxyFactory\:
|
||||
The AbstractProxyFactory class is deprecated since doctrine/common 3\.5\.$#
|
||||
'''
|
||||
identifier: staticMethod.deprecatedClass
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '''
|
||||
#^Call to method getProxy\(\) of deprecated class Doctrine\\Common\\Proxy\\AbstractProxyFactory\:
|
||||
The AbstractProxyFactory class is deprecated since doctrine/common 3\.5\.$#
|
||||
'''
|
||||
identifier: staticMethod.deprecatedClass
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '''
|
||||
#^Class Doctrine\\ORM\\Proxy\\ProxyFactory extends deprecated class Doctrine\\Common\\Proxy\\AbstractProxyFactory\:
|
||||
@@ -3243,15 +3168,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '''
|
||||
#^Instantiation of deprecated class Doctrine\\Common\\Proxy\\ProxyGenerator\:
|
||||
The ProxyGenerator class is deprecated since doctrine/common 3\.5\.$#
|
||||
'''
|
||||
identifier: new.deprecated
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createCloner\(\) has Doctrine\\ORM\\EntityNotFoundException in PHPDoc @throws tag but it''s not thrown\.$#'
|
||||
identifier: throws.unusedType
|
||||
@@ -3684,7 +3600,7 @@ parameters:
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Query\\Filter\\SQLFilter\:\:\$parameters \(array\<string, array\{type\: string, value\: mixed, is_list\: bool\}\>\) does not accept non\-empty\-array\<string, array\{value\: mixed, type\: int\|string, is_list\: bool\}\>\.$#'
|
||||
identifier: assign.propertyType
|
||||
count: 1
|
||||
count: 2
|
||||
path: src/Query/Filter/SQLFilter.php
|
||||
|
||||
-
|
||||
@@ -3987,12 +3903,6 @@ parameters:
|
||||
count: 5
|
||||
path: src/Query/SqlWalker.php
|
||||
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Query\\SqlWalker\:\:\$selectedClasses \(array\<string, array\{class\: Doctrine\\ORM\\Mapping\\ClassMetadata, dqlAlias\: string, resultAlias\: string\|null\}\>\) does not accept non\-empty\-array\<int\|string, array\{class\: Doctrine\\ORM\\Mapping\\ClassMetadata, dqlAlias\: mixed, resultAlias\: string\|null\}\>\.$#'
|
||||
identifier: assign.propertyType
|
||||
count: 1
|
||||
path: src/Query/SqlWalker.php
|
||||
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Query\\SqlWalker\:\:\$selectedClasses with generic class Doctrine\\ORM\\Mapping\\ClassMetadata does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -4269,12 +4179,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/ConvertMappingCommand.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$destPath of method Doctrine\\ORM\\Tools\\Console\\Command\\ConvertMappingCommand\:\:getExporter\(\) expects string, string\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/ConvertMappingCommand.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\Persistence\\Mapping\\ClassMetadata\:\:\$name\.$#'
|
||||
identifier: property.notFound
|
||||
@@ -4299,12 +4203,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/GenerateEntitiesCommand.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$outputDirectory of method Doctrine\\ORM\\Tools\\EntityGenerator\:\:generate\(\) expects string, string\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/GenerateEntitiesCommand.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\Persistence\\Mapping\\ClassMetadata\:\:\$name\.$#'
|
||||
identifier: property.notFound
|
||||
@@ -4323,12 +4221,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/GenerateProxiesCommand.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$proxyDir of method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateProxyClasses\(\) expects string\|null, string\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/GenerateProxiesCommand.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\Persistence\\Mapping\\ClassMetadata\:\:\$customRepositoryClassName\.$#'
|
||||
identifier: property.notFound
|
||||
@@ -4347,12 +4239,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/GenerateRepositoriesCommand.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$outputDirectory of method Doctrine\\ORM\\Tools\\EntityRepositoryGenerator\:\:writeEntityRepositoryClass\(\) expects string, string\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/GenerateRepositoriesCommand.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Tools\\Console\\Command\\MappingDescribeCommand\:\:formatMappings\(\) has parameter \$propertyMappings with no value type specified in iterable type array\.$#'
|
||||
identifier: missingType.iterableValue
|
||||
@@ -5067,6 +4953,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Tools/Pagination/LimitSubqueryOutputWalker.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Tools\\Pagination\\Paginator\:\:setUseOutputWalkers\(\) should return static\(Doctrine\\ORM\\Tools\\Pagination\\Paginator\<T\>\) but returns \$this\(Doctrine\\ORM\\Tools\\Pagination\\Paginator\<T\>\)\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Tools/Pagination/Paginator.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc tag @var for variable \$parameters contains generic interface Doctrine\\Common\\Collections\\Collection but does not specify its types\: TKey, T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -5091,12 +4983,6 @@ parameters:
|
||||
count: 5
|
||||
path: src/Tools/ResolveTargetEntityListener.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$className of method Doctrine\\Persistence\\Mapping\\AbstractClassMetadataFactory\<Doctrine\\ORM\\Mapping\\ClassMetadata\>\:\:setMetadataFor\(\) expects class\-string, \(int\|string\) given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/ResolveTargetEntityListener.php
|
||||
|
||||
-
|
||||
message: '#^Call to function is_numeric\(\) with int\<0, max\> will always evaluate to true\.$#'
|
||||
identifier: function.alreadyNarrowedType
|
||||
@@ -5589,8 +5475,26 @@ parameters:
|
||||
count: 1
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Utility\\PersisterHelper\:\:inferParameterTypes\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
-
|
||||
message: '#^Offset ''joinTable'' might not exist on array\{cache\?\: array, cascade\: array\<string\>, declared\?\: class\-string, fetch\: mixed, fieldName\: string, id\?\: bool, inherited\?\: class\-string, indexBy\?\: string, \.\.\.\}\.$#'
|
||||
identifier: offsetAccess.notFound
|
||||
count: 1
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
-
|
||||
message: '#^Offset ''relationToTargetKeyColumns'' might not exist on array\{cache\?\: array, cascade\: array\<string\>, declared\?\: class\-string, fetch\: mixed, fieldName\: string, id\?\: bool, inherited\?\: class\-string, indexBy\?\: string, \.\.\.\}\.$#'
|
||||
identifier: offsetAccess.notFound
|
||||
count: 1
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
-
|
||||
message: '#^Offset ''sourceToTargetKeyColumns'' might not exist on array\{cache\?\: array, cascade\: array\<string\>, declared\?\: class\-string, fetch\: mixed, fieldName\: string, id\?\: bool, inherited\?\: class\-string, indexBy\?\: string, \.\.\.\}\.$#'
|
||||
identifier: offsetAccess.notFound
|
||||
count: 1
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
@@ -57,6 +57,17 @@ parameters:
|
||||
count: 2
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#introspectSchema#'
|
||||
count: 2
|
||||
identifier: 'method.notFound'
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#getMaxIdentifierLength#'
|
||||
identifier: 'method.deprecatedClass'
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$start of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getSubstringExpression\\(\\) expects int, string given\\.$#"
|
||||
count: 1
|
||||
|
||||
@@ -100,3 +100,19 @@ parameters:
|
||||
-
|
||||
message: '#^Parameter \#1 \$classNames of method Doctrine\\ORM\\Mapping\\ClassMetadataInfo\<object\>\:\:setParentClasses\(\) expects list\<class\-string\>, array\<string\> given\.$#'
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
-
|
||||
message: '#loadMappingFile#'
|
||||
identifier: 'return.type'
|
||||
path: src/Mapping/Driver/XmlDriver.php
|
||||
|
||||
-
|
||||
message: '#injectObjectManager#'
|
||||
identifier: 'method.deprecatedInterface'
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '#^Static method Doctrine\\Common\\Collections\\Criteria\:\:create\(\) invoked with 1 parameter, 0 required\.$#'
|
||||
identifier: arguments.count
|
||||
count: 3
|
||||
path: src/Persisters/Collection/OneToManyPersister.php
|
||||
|
||||
21
run-all.sh
21
run-all.sh
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script is a small convenience wrapper for running the doctrine testsuite against a large bunch of databases.
|
||||
# Just create the phpunit.xmls as described in the array below and configure the specific files <php /> section
|
||||
# to connect to that database. Just omit a file if you don't have that database and the tests will be skipped.
|
||||
|
||||
configs[1]="mysql.phpunit.xml"
|
||||
configs[2]='postgres.phpunit.xml'
|
||||
configs[3]='sqlite.phpunit.xml'
|
||||
configs[4]='oracle.phpunit.xml'
|
||||
configs[5]='db2.phpunit.xml'
|
||||
configs[6]='pdo-ibm.phpunit.xml'
|
||||
configs[7]='sqlsrv.phpunit.xml'
|
||||
|
||||
for i in "${configs[@]}"; do
|
||||
if [ -f "$i" ];
|
||||
then
|
||||
echo "RUNNING TESTS WITH CONFIG $i"
|
||||
phpunit -c "$i" "$@"
|
||||
fi;
|
||||
done
|
||||
@@ -21,7 +21,6 @@ use Doctrine\ORM\Internal\Hydration\IterableResult;
|
||||
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Doctrine\ORM\Query\Parameter;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\Persistence\Mapping\MappingException;
|
||||
use LogicException;
|
||||
@@ -1144,10 +1143,6 @@ abstract class AbstractQuery
|
||||
throw new LogicException('Uninitialized result set mapping.');
|
||||
}
|
||||
|
||||
if ($rsm->isMixed && count($rsm->scalarMappings) > 0) {
|
||||
throw QueryException::iterateWithMixedResultNotAllowed();
|
||||
}
|
||||
|
||||
$stmt = $this->_doExecute();
|
||||
|
||||
return $this->_em->newHydrator($this->_hydrationMode)->toIterable($stmt, $rsm, $this->_hints);
|
||||
|
||||
@@ -59,7 +59,10 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
$targetRegion = $targetPersister->getCacheRegion();
|
||||
$list = [];
|
||||
|
||||
/** @var EntityCacheEntry[]|null $entityEntries */
|
||||
/**
|
||||
* @var EntityCacheEntry[]|null $entityEntries
|
||||
* @phpstan-ignore method.deprecatedInterface
|
||||
*/
|
||||
$entityEntries = $targetRegion->getMultiple($entry);
|
||||
|
||||
if ($entityEntries === null) {
|
||||
|
||||
@@ -103,7 +103,8 @@ class DefaultQueryCache implements QueryCache
|
||||
};
|
||||
|
||||
$cacheKeys = new CollectionCacheEntry(array_map($generateKeys, $cacheEntry->result));
|
||||
$entries = $region->getMultiple($cacheKeys) ?? [];
|
||||
/** @phpstan-ignore method.deprecatedInterface */
|
||||
$entries = $region->getMultiple($cacheKeys) ?? [];
|
||||
|
||||
// @TODO - move to cache hydration component
|
||||
foreach ($cacheEntry->result as $index => $entry) {
|
||||
@@ -167,8 +168,9 @@ class DefaultQueryCache implements QueryCache
|
||||
return new EntityCacheKey($assocMetadata->rootEntityName, $id);
|
||||
};
|
||||
|
||||
$collection = new PersistentCollection($this->em, $assocMetadata, new ArrayCollection());
|
||||
$assocKeys = new CollectionCacheEntry(array_map($generateKeys, $assoc['list']));
|
||||
$collection = new PersistentCollection($this->em, $assocMetadata, new ArrayCollection());
|
||||
$assocKeys = new CollectionCacheEntry(array_map($generateKeys, $assoc['list']));
|
||||
/** @phpstan-ignore method.deprecatedInterface */
|
||||
$assocEntries = $assocRegion->getMultiple($assocKeys);
|
||||
|
||||
foreach ($assoc['list'] as $assocIndex => $assocId) {
|
||||
|
||||
@@ -156,6 +156,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @phpstan-ignore method.deprecatedInterface */
|
||||
return $this->region->getMultiple($collection);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
*/
|
||||
public function __construct($entity, EntityManagerInterface $em, array &$changeSet)
|
||||
{
|
||||
// @phpstan-ignore staticMethod.deprecatedClass
|
||||
// @phpstan-ignore method.deprecatedClass
|
||||
parent::__construct($entity, $em);
|
||||
|
||||
$this->entityChangeSet = &$changeSet;
|
||||
|
||||
@@ -25,10 +25,12 @@ use TypeError;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use function current;
|
||||
use function end;
|
||||
use function get_debug_type;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
@@ -201,8 +203,10 @@ abstract class AbstractHydrator
|
||||
} else {
|
||||
yield from $result;
|
||||
}
|
||||
} else {
|
||||
} elseif (is_object(current($result))) {
|
||||
yield $result;
|
||||
} else {
|
||||
yield array_merge(...$result);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -722,7 +722,7 @@ DEPRECATION
|
||||
'Mapping for %s: the "UUID" id generator strategy is deprecated with no replacement',
|
||||
$class->name
|
||||
);
|
||||
// @phpstan-ignore new.deprecated
|
||||
// @phpstan-ignore method.deprecatedClass, new.deprecatedClass
|
||||
$class->setIdGenerator(new UuidGenerator());
|
||||
break;
|
||||
|
||||
|
||||
@@ -32,13 +32,8 @@ trait ReflectionBasedDriver
|
||||
|| $metadata->isInheritedEmbeddedClass($property->name);
|
||||
}
|
||||
|
||||
/** @var class-string $declaringClass */
|
||||
$declaringClass = $property->class;
|
||||
|
||||
if ($this->isTransient($declaringClass)) {
|
||||
return isset($metadata->fieldMappings[$property->name]);
|
||||
}
|
||||
|
||||
if (
|
||||
isset($metadata->fieldMappings[$property->name]['declared'])
|
||||
&& $metadata->fieldMappings[$property->name]['declared'] === $declaringClass
|
||||
|
||||
@@ -10,8 +10,6 @@ use Doctrine\Persistence\Mapping\Driver\SymfonyFileLocator;
|
||||
* YamlDriver that additionally looks for mapping information in a global file.
|
||||
*
|
||||
* @deprecated This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class SimplifiedYamlDriver extends YamlDriver
|
||||
{
|
||||
|
||||
@@ -206,7 +206,6 @@ class XmlDriver extends FileDriver
|
||||
];
|
||||
|
||||
if (isset($discrColumn['options'])) {
|
||||
assert($discrColumn['options'] instanceof SimpleXMLElement);
|
||||
$columnDef['options'] = $this->parseOptions($discrColumn['options']->children());
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Utility\PersisterHelper;
|
||||
|
||||
use function array_fill;
|
||||
use function array_merge;
|
||||
use function array_pop;
|
||||
use function count;
|
||||
use function get_class;
|
||||
@@ -256,10 +257,17 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
|
||||
if ($value === null && ($operator === Comparison::EQ || $operator === Comparison::NEQ)) {
|
||||
$whereClauses[] = sprintf('te.%s %s NULL', $field, $operator === Comparison::EQ ? 'IS' : 'IS NOT');
|
||||
} elseif ($operator === Comparison::IN || $operator === Comparison::NIN) {
|
||||
$whereClauses[] = sprintf('te.%s %s (%s)', $field, $operator === Comparison::IN ? 'IN' : 'NOT IN', implode(', ', array_fill(0, count($value), '?')));
|
||||
foreach ($value as $item) {
|
||||
$params = array_merge($params, PersisterHelper::convertToParameterValue($item, $this->em));
|
||||
$paramTypes = array_merge($paramTypes, PersisterHelper::inferParameterTypes($name, $item, $targetClass, $this->em));
|
||||
}
|
||||
} else {
|
||||
$whereClauses[] = sprintf('te.%s %s ?', $field, $operator);
|
||||
$params[] = $value;
|
||||
$paramTypes[] = PersisterHelper::getTypeOfField($name, $targetClass, $this->em)[0];
|
||||
|
||||
$params = array_merge($params, PersisterHelper::convertToParameterValue($value, $this->em));
|
||||
$paramTypes = array_merge($paramTypes, PersisterHelper::inferParameterTypes($name, $value, $targetClass, $this->em));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
// only works with single id identifier entities. Will throw an
|
||||
// exception in Entity Persisters if that is not the case for the
|
||||
// 'mappedBy' field.
|
||||
$criteria = new Criteria(Criteria::expr()->eq($mapping['mappedBy'], $collection->getOwner()));
|
||||
$criteria = Criteria::create(true)->where(Criteria::expr()->eq($mapping['mappedBy'], $collection->getOwner()));
|
||||
|
||||
return $persister->count($criteria);
|
||||
}
|
||||
@@ -135,7 +135,7 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
// only works with single id identifier entities. Will throw an
|
||||
// exception in Entity Persisters if that is not the case for the
|
||||
// 'mappedBy' field.
|
||||
$criteria = new Criteria();
|
||||
$criteria = Criteria::create(true);
|
||||
|
||||
$criteria->andWhere(Criteria::expr()->eq($mapping['mappedBy'], $collection->getOwner()));
|
||||
$criteria->andWhere(Criteria::expr()->eq($mapping['indexBy'], $key));
|
||||
@@ -158,7 +158,7 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
// only works with single id identifier entities. Will throw an
|
||||
// exception in Entity Persisters if that is not the case for the
|
||||
// 'mappedBy' field.
|
||||
$criteria = new Criteria(Criteria::expr()->eq($mapping['mappedBy'], $collection->getOwner()));
|
||||
$criteria = Criteria::create(true)->where(Criteria::expr()->eq($mapping['mappedBy'], $collection->getOwner()));
|
||||
|
||||
return $persister->exists($element, $criteria);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Persisters\Entity;
|
||||
|
||||
use BackedEnum;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\Expr\Comparison;
|
||||
use Doctrine\DBAL\Connection;
|
||||
@@ -26,9 +25,7 @@ use Doctrine\ORM\Persisters\Exception\InvalidOrientation;
|
||||
use Doctrine\ORM\Persisters\Exception\UnrecognizedField;
|
||||
use Doctrine\ORM\Persisters\SqlExpressionVisitor;
|
||||
use Doctrine\ORM\Persisters\SqlValueVisitor;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Repository\Exception\InvalidFindByCall;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\ORM\Utility\IdentifierFlattener;
|
||||
@@ -37,17 +34,18 @@ use Doctrine\ORM\Utility\PersisterHelper;
|
||||
use LengthException;
|
||||
|
||||
use function array_combine;
|
||||
use function array_diff_key;
|
||||
use function array_fill;
|
||||
use function array_flip;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function array_search;
|
||||
use function array_unique;
|
||||
use function array_values;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function reset;
|
||||
use function spl_object_id;
|
||||
use function sprintf;
|
||||
@@ -394,7 +392,7 @@ class BasicEntityPersister implements EntityPersister
|
||||
$types = [];
|
||||
|
||||
foreach ($id as $field => $value) {
|
||||
$types = array_merge($types, $this->getTypes($field, $value, $versionedClass));
|
||||
$types = array_merge($types, PersisterHelper::inferParameterTypes($field, $value, $versionedClass, $this->em));
|
||||
}
|
||||
|
||||
return $types;
|
||||
@@ -955,8 +953,31 @@ class BasicEntityPersister implements EntityPersister
|
||||
continue;
|
||||
}
|
||||
|
||||
$sqlParams = array_merge($sqlParams, $this->getValues($value));
|
||||
$sqlTypes = array_merge($sqlTypes, $this->getTypes($field, $value, $this->class));
|
||||
if ($operator === Comparison::IN || $operator === Comparison::NIN) {
|
||||
if (! is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
|
||||
foreach ($value as $item) {
|
||||
if ($item === null) {
|
||||
/*
|
||||
* Compare this to how \Doctrine\ORM\Persisters\Entity\BasicEntityPersister::getSelectConditionStatementSQL
|
||||
* creates the "[NOT] IN (...)" expression - for NULL values, it does _not_ insert a placeholder in the
|
||||
* SQL and instead adds an extra ... OR ... IS NULL condition. So we need to skip NULL values here as
|
||||
* well to create a parameters list that matches the SQL.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
$sqlParams = array_merge($sqlParams, PersisterHelper::convertToParameterValue($item, $this->em));
|
||||
$sqlTypes = array_merge($sqlTypes, PersisterHelper::inferParameterTypes($field, $item, $this->class, $this->em));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$sqlParams = array_merge($sqlParams, PersisterHelper::convertToParameterValue($value, $this->em));
|
||||
$sqlTypes = array_merge($sqlTypes, PersisterHelper::inferParameterTypes($field, $value, $this->class, $this->em));
|
||||
}
|
||||
|
||||
return [$sqlParams, $sqlTypes];
|
||||
@@ -1693,6 +1714,8 @@ class BasicEntityPersister implements EntityPersister
|
||||
*/
|
||||
public function getSelectConditionStatementSQL($field, $value, $assoc = null, $comparison = null)
|
||||
{
|
||||
$comparison = $comparison ?? (is_array($value) ? Comparison::IN : Comparison::EQ);
|
||||
|
||||
$selectedColumns = [];
|
||||
$columns = $this->getSelectConditionStatementColumnSQL($field, $assoc);
|
||||
|
||||
@@ -1712,46 +1735,50 @@ class BasicEntityPersister implements EntityPersister
|
||||
$placeholder = $type->convertToDatabaseValueSQL($placeholder, $this->platform);
|
||||
}
|
||||
|
||||
if ($comparison !== null) {
|
||||
// special case null value handling
|
||||
if (($comparison === Comparison::EQ || $comparison === Comparison::IS) && $value === null) {
|
||||
$selectedColumns[] = $column . ' IS NULL';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($comparison === Comparison::NEQ && $value === null) {
|
||||
$selectedColumns[] = $column . ' IS NOT NULL';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$selectedColumns[] = $column . ' ' . sprintf(self::$comparisonMap[$comparison], $placeholder);
|
||||
// special case null value handling
|
||||
if (($comparison === Comparison::EQ || $comparison === Comparison::IS) && $value === null) {
|
||||
$selectedColumns[] = $column . ' IS NULL';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
$in = sprintf('%s IN (%s)', $column, $placeholder);
|
||||
if ($comparison === Comparison::NEQ && $value === null) {
|
||||
$selectedColumns[] = $column . ' IS NOT NULL';
|
||||
|
||||
if (array_search(null, $value, true) !== false) {
|
||||
$selectedColumns[] = sprintf('(%s OR %s IS NULL)', $in, $column);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($comparison === Comparison::IN || $comparison === Comparison::NIN) {
|
||||
if (! is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
|
||||
if ($value === []) {
|
||||
$selectedColumns[] = '1=0';
|
||||
continue;
|
||||
}
|
||||
|
||||
$selectedColumns[] = $in;
|
||||
$nullKeys = array_keys($value, null, true);
|
||||
$nonNullValues = array_diff_key($value, array_flip($nullKeys));
|
||||
|
||||
$placeholders = implode(', ', array_fill(0, count($nonNullValues), $placeholder));
|
||||
|
||||
$in = $column . ' ' . sprintf(self::$comparisonMap[$comparison], $placeholders);
|
||||
|
||||
if ($nullKeys) {
|
||||
if ($nonNullValues) {
|
||||
$selectedColumns[] = sprintf('(%s OR %s IS NULL)', $in, $column);
|
||||
} else {
|
||||
$selectedColumns[] = $column . ' IS NULL';
|
||||
}
|
||||
} else {
|
||||
$selectedColumns[] = $in;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value === null) {
|
||||
$selectedColumns[] = sprintf('%s IS NULL', $column);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$selectedColumns[] = sprintf('%s = %s', $column, $placeholder);
|
||||
$selectedColumns[] = $column . ' ' . sprintf(self::$comparisonMap[$comparison], $placeholder);
|
||||
}
|
||||
|
||||
return implode(' AND ', $selectedColumns);
|
||||
@@ -1942,8 +1969,18 @@ class BasicEntityPersister implements EntityPersister
|
||||
continue; // skip null values.
|
||||
}
|
||||
|
||||
$types = array_merge($types, $this->getTypes($field, $value, $this->class));
|
||||
$params = array_merge($params, $this->getValues($value));
|
||||
if (is_array($value)) {
|
||||
$nonNullValues = array_diff_key($value, array_flip(array_keys($value, null, true)));
|
||||
foreach ($nonNullValues as $item) {
|
||||
$types = array_merge($types, PersisterHelper::inferParameterTypes($field, $item, $this->class, $this->em));
|
||||
$params = array_merge($params, PersisterHelper::convertToParameterValue($item, $this->em));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$types = array_merge($types, PersisterHelper::inferParameterTypes($field, $value, $this->class, $this->em));
|
||||
$params = array_merge($params, PersisterHelper::convertToParameterValue($value, $this->em));
|
||||
}
|
||||
|
||||
return [$params, $types];
|
||||
@@ -1971,127 +2008,13 @@ class BasicEntityPersister implements EntityPersister
|
||||
continue; // skip null values.
|
||||
}
|
||||
|
||||
$types = array_merge($types, $this->getTypes($criterion['field'], $criterion['value'], $criterion['class']));
|
||||
$params = array_merge($params, $this->getValues($criterion['value']));
|
||||
$types = array_merge($types, PersisterHelper::inferParameterTypes($criterion['field'], $criterion['value'], $criterion['class'], $this->em));
|
||||
$params = array_merge($params, PersisterHelper::convertToParameterValue($criterion['value'], $this->em));
|
||||
}
|
||||
|
||||
return [$params, $types];
|
||||
}
|
||||
|
||||
/**
|
||||
* Infers field types to be used by parameter type casting.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return int[]|null[]|string[]
|
||||
* @phpstan-return list<int|string|null>
|
||||
*
|
||||
* @throws QueryException
|
||||
*/
|
||||
private function getTypes(string $field, $value, ClassMetadata $class): array
|
||||
{
|
||||
$types = [];
|
||||
|
||||
switch (true) {
|
||||
case isset($class->fieldMappings[$field]):
|
||||
$types = array_merge($types, [$class->fieldMappings[$field]['type']]);
|
||||
break;
|
||||
|
||||
case isset($class->associationMappings[$field]):
|
||||
$assoc = $class->associationMappings[$field];
|
||||
$class = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||
|
||||
if (! $assoc['isOwningSide']) {
|
||||
$assoc = $class->associationMappings[$assoc['mappedBy']];
|
||||
$class = $this->em->getClassMetadata($assoc['targetEntity']);
|
||||
}
|
||||
|
||||
$columns = $assoc['type'] === ClassMetadata::MANY_TO_MANY
|
||||
? $assoc['relationToTargetKeyColumns']
|
||||
: $assoc['sourceToTargetKeyColumns'];
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$types[] = PersisterHelper::getTypeOfColumn($column, $class, $this->em);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$types[] = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return array_map(static function ($type) {
|
||||
$type = Type::getType($type);
|
||||
|
||||
return $type->getBindingType() + Connection::ARRAY_PARAM_OFFSET;
|
||||
}, $types);
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the parameters that identifies a value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function getValues($value): array
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$newValue = [];
|
||||
|
||||
foreach ($value as $itemValue) {
|
||||
$newValue = array_merge($newValue, $this->getValues($itemValue));
|
||||
}
|
||||
|
||||
return [$newValue];
|
||||
}
|
||||
|
||||
return $this->getIndividualValue($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an individual parameter value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @phpstan-return list<mixed>
|
||||
*/
|
||||
private function getIndividualValue($value): array
|
||||
{
|
||||
if (! is_object($value)) {
|
||||
return [$value];
|
||||
}
|
||||
|
||||
if ($value instanceof BackedEnum) {
|
||||
return [$value->value];
|
||||
}
|
||||
|
||||
$valueClass = DefaultProxyClassNameResolver::getClass($value);
|
||||
|
||||
if ($this->em->getMetadataFactory()->isTransient($valueClass)) {
|
||||
return [$value];
|
||||
}
|
||||
|
||||
$class = $this->em->getClassMetadata($valueClass);
|
||||
|
||||
if ($class->isIdentifierComposite) {
|
||||
$newValue = [];
|
||||
|
||||
foreach ($class->getIdentifierValues($value) as $innerValue) {
|
||||
$newValue = array_merge($newValue, $this->getValues($innerValue));
|
||||
}
|
||||
|
||||
return $newValue;
|
||||
}
|
||||
|
||||
return [$this->em->getUnitOfWork()->getSingleIdentifierValue($value)];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
||||
@@ -73,7 +73,7 @@ interface EntityPersister
|
||||
/**
|
||||
* Expands the parameters from the given criteria and use the correct binding types if found.
|
||||
*
|
||||
* @param string[] $criteria
|
||||
* @param array<string, mixed> $criteria
|
||||
*
|
||||
* @phpstan-return array{list<mixed>, list<int|string|null>}
|
||||
*/
|
||||
@@ -258,6 +258,8 @@ interface EntityPersister
|
||||
* @param int|null $offset
|
||||
* @phpstan-param array<string, string>|null $orderBy
|
||||
* @phpstan-param array<string, mixed> $criteria
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function loadAll(array $criteria = [], ?array $orderBy = null, $limit = null, $offset = null);
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
*/
|
||||
private function getVersionedClassMetadata(): ClassMetadata
|
||||
{
|
||||
if (isset($this->class->fieldMappings[$this->class->versionField]['inherited'])) {
|
||||
if ($this->class->versionField !== null && isset($this->class->fieldMappings[$this->class->versionField]['inherited'])) {
|
||||
$definingClassName = $this->class->fieldMappings[$this->class->versionField]['inherited'];
|
||||
|
||||
return $this->em->getClassMetadata($definingClassName);
|
||||
|
||||
@@ -172,10 +172,12 @@ EOPHP;
|
||||
|
||||
$this->isLazyGhostObjectEnabled = false;
|
||||
|
||||
// @phpstan-ignore new.deprecatedClass, method.deprecatedClass
|
||||
$proxyGenerator = new ProxyGenerator($proxyDir, $proxyNs);
|
||||
// @phpstan-ignore classConstant.deprecatedInterface
|
||||
// @phpstan-ignore classConstant.deprecatedInterface, method.deprecatedClass
|
||||
$proxyGenerator->setPlaceholder('baseProxyInterface', LegacyProxy::class);
|
||||
|
||||
// @phpstan-ignore method.deprecatedClass
|
||||
parent::__construct($proxyGenerator, $em->getMetadataFactory(), $autoGenerate);
|
||||
}
|
||||
|
||||
@@ -205,6 +207,7 @@ EOPHP;
|
||||
public function getProxy($className, array $identifier)
|
||||
{
|
||||
if (! $this->isLazyGhostObjectEnabled) {
|
||||
// @phpstan-ignore method.deprecatedClass
|
||||
return parent::getProxy($className, $identifier);
|
||||
}
|
||||
|
||||
@@ -226,6 +229,7 @@ EOPHP;
|
||||
public function generateProxyClasses(array $classes, $proxyDir = null)
|
||||
{
|
||||
if (! $this->isLazyGhostObjectEnabled) {
|
||||
// @phpstan-ignore method.deprecatedClass
|
||||
return parent::generateProxyClasses($classes, $proxyDir);
|
||||
}
|
||||
|
||||
@@ -422,7 +426,10 @@ EOPHP;
|
||||
continue;
|
||||
}
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$property->setValue($proxy, $property->getValue($original));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,9 +14,10 @@ class InListExpression extends InExpression
|
||||
public function __construct(ArithmeticExpression $expression, array $literals, bool $not = false)
|
||||
{
|
||||
$this->literals = $literals;
|
||||
$this->not = $not;
|
||||
// @phpstan-ignore property.deprecatedClass
|
||||
$this->not = $not;
|
||||
|
||||
// @phpstan-ignore staticMethod.deprecatedClass
|
||||
// @phpstan-ignore method.deprecatedClass
|
||||
parent::__construct($expression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,10 @@ class InSubselectExpression extends InExpression
|
||||
public function __construct(ArithmeticExpression $expression, Subselect $subselect, bool $not = false)
|
||||
{
|
||||
$this->subselect = $subselect;
|
||||
$this->not = $not;
|
||||
// @phpstan-ignore property.deprecatedClass
|
||||
$this->not = $not;
|
||||
|
||||
// @phpstan-ignore staticMethod.deprecatedClass
|
||||
// @phpstan-ignore method.deprecatedClass
|
||||
parent::__construct($expression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ class ResultSetMappingBuilder extends ResultSetMapping
|
||||
[$relation, $fieldName] = explode('.', $fieldName);
|
||||
}
|
||||
|
||||
if (isset($classMetadata->associationMappings[$relation])) {
|
||||
if ($relation !== null && isset($classMetadata->associationMappings[$relation])) {
|
||||
if ($relation) {
|
||||
$associationMapping = $classMetadata->associationMappings[$relation];
|
||||
$joinAlias = $alias . $relation;
|
||||
|
||||
@@ -1587,7 +1587,9 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
$sqlParts[] = $col . ' AS ' . $columnAlias;
|
||||
|
||||
$this->scalarResultAliasMap[$resultAlias][] = $columnAlias;
|
||||
if ($resultAlias !== null) {
|
||||
$this->scalarResultAliasMap[$resultAlias][] = $columnAlias;
|
||||
}
|
||||
|
||||
$this->rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name);
|
||||
|
||||
@@ -1622,7 +1624,9 @@ class SqlWalker implements TreeWalker
|
||||
|
||||
$sqlParts[] = $col . ' AS ' . $columnAlias;
|
||||
|
||||
$this->scalarResultAliasMap[$resultAlias][] = $columnAlias;
|
||||
if ($resultAlias !== null) {
|
||||
$this->scalarResultAliasMap[$resultAlias][] = $columnAlias;
|
||||
}
|
||||
|
||||
$this->rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName);
|
||||
}
|
||||
@@ -2356,7 +2360,9 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
public function walkInListExpression(AST\InListExpression $inExpr): string
|
||||
{
|
||||
/** @phpstan-ignore property.deprecatedClass */
|
||||
return $this->walkArithmeticExpression($inExpr->expression)
|
||||
/** @phpstan-ignore property.deprecatedClass */
|
||||
. ($inExpr->not ? ' NOT' : '') . ' IN ('
|
||||
. implode(', ', array_map([$this, 'walkInParameter'], $inExpr->literals))
|
||||
. ')';
|
||||
@@ -2367,7 +2373,9 @@ class SqlWalker implements TreeWalker
|
||||
*/
|
||||
public function walkInSubselectExpression(AST\InSubselectExpression $inExpr): string
|
||||
{
|
||||
/** @phpstan-ignore property.deprecatedClass */
|
||||
return $this->walkArithmeticExpression($inExpr->expression)
|
||||
/** @phpstan-ignore property.deprecatedClass */
|
||||
. ($inExpr->not ? ' NOT' : '') . ' IN ('
|
||||
. $this->walkSubselect($inExpr->subselect)
|
||||
. ')';
|
||||
|
||||
@@ -39,6 +39,7 @@ abstract class AbstractEntityManagerCommand extends Command
|
||||
$helper = $this->getHelper('em');
|
||||
assert($helper instanceof EntityManagerHelper);
|
||||
|
||||
/** @phpstan-ignore method.deprecatedClass */
|
||||
return $helper->getEntityManager();
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ final class ConsoleRunner
|
||||
if ($helperSetOrProvider instanceof HelperSet) {
|
||||
$cli->setHelperSet($helperSetOrProvider);
|
||||
|
||||
// @phpstan-ignore new.deprecated
|
||||
// @phpstan-ignore new.deprecatedClass, method.deprecatedClass
|
||||
$helperSetOrProvider = new HelperSetManagerProvider($helperSetOrProvider);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ final class ConsoleRunner
|
||||
public static function addCommands(Application $cli, ?EntityManagerProvider $entityManagerProvider = null): void
|
||||
{
|
||||
if ($entityManagerProvider === null) {
|
||||
// @phpstan-ignore new.deprecated
|
||||
// @phpstan-ignore new.deprecatedClass, method.deprecatedClass
|
||||
$entityManagerProvider = new HelperSetManagerProvider($cli->getHelperSet());
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ final class ConsoleRunner
|
||||
$cli->addCommands(
|
||||
[
|
||||
// DBAL Commands
|
||||
// @phpstan-ignore new.deprecated
|
||||
// @phpstan-ignore new.deprecatedClass, method.deprecatedClass
|
||||
new DBALConsole\Command\ReservedWordsCommand($connectionProvider),
|
||||
new DBALConsole\Command\RunSqlCommand($connectionProvider),
|
||||
|
||||
@@ -113,16 +113,16 @@ final class ConsoleRunner
|
||||
new Command\SchemaTool\CreateCommand($entityManagerProvider),
|
||||
new Command\SchemaTool\UpdateCommand($entityManagerProvider),
|
||||
new Command\SchemaTool\DropCommand($entityManagerProvider),
|
||||
// @phpstan-ignore new.deprecated
|
||||
// @phpstan-ignore new.deprecatedClass
|
||||
new Command\EnsureProductionSettingsCommand($entityManagerProvider),
|
||||
// @phpstan-ignore new.deprecated
|
||||
// @phpstan-ignore new.deprecatedClass
|
||||
new Command\ConvertDoctrine1SchemaCommand(),
|
||||
// @phpstan-ignore new.deprecated
|
||||
// @phpstan-ignore new.deprecatedClass
|
||||
new Command\GenerateRepositoriesCommand($entityManagerProvider),
|
||||
// @phpstan-ignore new.deprecated
|
||||
// @phpstan-ignore new.deprecatedClass
|
||||
new Command\GenerateEntitiesCommand($entityManagerProvider),
|
||||
new Command\GenerateProxiesCommand($entityManagerProvider),
|
||||
// @phpstan-ignore new.deprecated
|
||||
// @phpstan-ignore new.deprecatedClass
|
||||
new Command\ConvertMappingCommand($entityManagerProvider),
|
||||
new Command\RunDqlCommand($entityManagerProvider),
|
||||
new Command\ValidateSchemaCommand($entityManagerProvider),
|
||||
|
||||
@@ -16,8 +16,6 @@ use function str_replace;
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class AnnotationExporter extends AbstractExporter
|
||||
{
|
||||
|
||||
@@ -23,8 +23,6 @@ use const PHP_EOL;
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class PhpExporter extends AbstractExporter
|
||||
{
|
||||
|
||||
@@ -21,8 +21,6 @@ use function uasort;
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class XmlExporter extends AbstractExporter
|
||||
{
|
||||
|
||||
@@ -16,8 +16,6 @@ use function count;
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class YamlExporter extends AbstractExporter
|
||||
{
|
||||
|
||||
@@ -149,7 +149,9 @@ class LimitSubqueryOutputWalker extends SqlOutputWalker
|
||||
$selectAliasToExpressionMap = [];
|
||||
// Get any aliases that are available for select expressions.
|
||||
foreach ($AST->selectClause->selectExpressions as $selectExpression) {
|
||||
$selectAliasToExpressionMap[$selectExpression->fieldIdentificationVariable] = $selectExpression->expression;
|
||||
if ($selectExpression->fieldIdentificationVariable !== null) {
|
||||
$selectAliasToExpressionMap[$selectExpression->fieldIdentificationVariable] = $selectExpression->expression;
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild string orderby expressions to use the select expression they're referencing
|
||||
|
||||
@@ -228,7 +228,22 @@ class Paginator implements Countable, IteratorAggregate
|
||||
*/
|
||||
private function getCountQuery(): Query
|
||||
{
|
||||
$countQuery = $this->cloneQuery($this->query);
|
||||
/*
|
||||
As opposed to using self::cloneQuery, the following code does not transfer
|
||||
a potentially existing result set mapping (either set directly by the user,
|
||||
or taken from the parser result from a previous invocation of Query::parse())
|
||||
to the new query object. This is fine, since we are going to completely change the
|
||||
select clause, so a previously existing result set mapping (RSM) is probably wrong anyway.
|
||||
In the case of using output walkers, we are even creating a new RSM down below.
|
||||
In the case of using a tree walker, we want to have a new RSM created by the parser.
|
||||
*/
|
||||
$countQuery = new Query($this->query->getEntityManager());
|
||||
$countQuery->setDQL($this->query->getDQL());
|
||||
$countQuery->setParameters(clone $this->query->getParameters());
|
||||
$countQuery->setCacheable(false);
|
||||
foreach ($this->query->getHints() as $name => $value) {
|
||||
$countQuery->setHint($name, $value);
|
||||
}
|
||||
|
||||
if (! $countQuery->hasHint(CountWalker::HINT_DISTINCT)) {
|
||||
$countQuery->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
|
||||
@@ -86,12 +86,6 @@ class ResolveTargetEntityListener implements EventSubscriber
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->resolveTargetEntities as $interface => $data) {
|
||||
if ($data['targetEntity'] === $cm->getName()) {
|
||||
$args->getEntityManager()->getMetadataFactory()->setMetadataFor($interface, $cm);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($cm->discriminatorMap as $value => $class) {
|
||||
if (isset($this->resolveTargetEntities[$class])) {
|
||||
$cm->addDiscriminatorMapClass($value, $this->resolveTargetEntities[$class]['targetEntity']);
|
||||
|
||||
@@ -413,7 +413,7 @@ class SchemaTool
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (array_filter($schema->getSequences() + $schema->getTables(), $filter) && ! $this->platform->canEmulateSchemas()) {
|
||||
// @phpstan-ignore method.deprecated, new.deprecated
|
||||
// @phpstan-ignore method.deprecated, method.deprecatedClass, new.deprecatedClass
|
||||
$schema->visit(new RemoveNamespacedAssets());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,8 @@ use function spl_object_id;
|
||||
use function sprintf;
|
||||
use function strtolower;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/**
|
||||
* The UnitOfWork is responsible for tracking changes to objects during an
|
||||
* "object-level" transaction and for writing out changes to the database
|
||||
@@ -3886,7 +3888,9 @@ EXCEPTION
|
||||
foreach ($this->reflectionPropertiesGetter->getProperties($class->name) as $prop) {
|
||||
$name = $prop->name;
|
||||
|
||||
$prop->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$prop->setAccessible(true);
|
||||
}
|
||||
|
||||
if (! isset($class->associationMappings[$name])) {
|
||||
if (! $class->isIdentifier($name)) {
|
||||
|
||||
@@ -4,11 +4,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Utility;
|
||||
|
||||
use BackedEnum;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use RuntimeException;
|
||||
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
@@ -113,4 +121,116 @@ class PersisterHelper
|
||||
$class->getName()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Infers field types to be used by parameter type casting.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return int[]|null[]|string[]
|
||||
* @phpstan-return list<int|string|null>
|
||||
*
|
||||
* @throws QueryException
|
||||
*/
|
||||
public static function inferParameterTypes(string $field, $value, ClassMetadata $class, EntityManagerInterface $em): array
|
||||
{
|
||||
$types = [];
|
||||
|
||||
switch (true) {
|
||||
case isset($class->fieldMappings[$field]):
|
||||
$types = array_merge($types, [$class->fieldMappings[$field]['type']]);
|
||||
break;
|
||||
|
||||
case isset($class->associationMappings[$field]):
|
||||
$assoc = $class->associationMappings[$field];
|
||||
$class = $em->getClassMetadata($assoc['targetEntity']);
|
||||
|
||||
if (! $assoc['isOwningSide']) {
|
||||
$assoc = $class->associationMappings[$assoc['mappedBy']];
|
||||
$class = $em->getClassMetadata($assoc['targetEntity']);
|
||||
}
|
||||
|
||||
$columns = $assoc['type'] === ClassMetadata::MANY_TO_MANY
|
||||
? $assoc['relationToTargetKeyColumns']
|
||||
: $assoc['sourceToTargetKeyColumns'];
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$types[] = self::getTypeOfColumn($column, $class, $em);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$types[] = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return array_map(static function ($type) {
|
||||
$type = Type::getType($type);
|
||||
|
||||
return $type->getBindingType() + Connection::ARRAY_PARAM_OFFSET;
|
||||
}, $types);
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a value to the type and value required to bind it as a parameter.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return list<mixed>
|
||||
*/
|
||||
public static function convertToParameterValue($value, EntityManagerInterface $em): array
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$newValue = [];
|
||||
|
||||
foreach ($value as $itemValue) {
|
||||
$newValue = array_merge($newValue, self::convertToParameterValue($itemValue, $em));
|
||||
}
|
||||
|
||||
return [$newValue];
|
||||
}
|
||||
|
||||
return self::convertIndividualValue($value, $em);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @phpstan-return list<mixed>
|
||||
*/
|
||||
private static function convertIndividualValue($value, EntityManagerInterface $em): array
|
||||
{
|
||||
if (! is_object($value)) {
|
||||
return [$value];
|
||||
}
|
||||
|
||||
if ($value instanceof BackedEnum) {
|
||||
return [$value->value];
|
||||
}
|
||||
|
||||
$valueClass = DefaultProxyClassNameResolver::getClass($value);
|
||||
|
||||
if ($em->getMetadataFactory()->isTransient($valueClass)) {
|
||||
return [$value];
|
||||
}
|
||||
|
||||
$class = $em->getClassMetadata($valueClass);
|
||||
|
||||
if ($class->isIdentifierComposite) {
|
||||
$newValue = [];
|
||||
|
||||
foreach ($class->getIdentifierValues($value) as $innerValue) {
|
||||
$newValue = array_merge($newValue, self::convertToParameterValue($innerValue, $em));
|
||||
}
|
||||
|
||||
return $newValue;
|
||||
}
|
||||
|
||||
return [$em->getUnitOfWork()->getSingleIdentifierValue($value)];
|
||||
}
|
||||
}
|
||||
|
||||
30
tests/Tests/Models/Enums/BookCategory.php
Normal file
30
tests/Tests/Models/Enums/BookCategory.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\Enums;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\GeneratedValue;
|
||||
use Doctrine\ORM\Mapping\Id;
|
||||
use Doctrine\ORM\Mapping\ManyToMany;
|
||||
|
||||
#[Entity]
|
||||
class BookCategory
|
||||
{
|
||||
#[Id]
|
||||
#[Column]
|
||||
#[GeneratedValue]
|
||||
public int $id;
|
||||
|
||||
#[ManyToMany(targetEntity: BookWithGenre::class, mappedBy: 'categories')]
|
||||
public Collection $books;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->books = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
11
tests/Tests/Models/Enums/BookGenre.php
Normal file
11
tests/Tests/Models/Enums/BookGenre.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\Enums;
|
||||
|
||||
enum BookGenre: string
|
||||
{
|
||||
case FICTION = 'fiction';
|
||||
case NON_FICTION = 'non fiction';
|
||||
}
|
||||
38
tests/Tests/Models/Enums/BookWithGenre.php
Normal file
38
tests/Tests/Models/Enums/BookWithGenre.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\Enums;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\GeneratedValue;
|
||||
use Doctrine\ORM\Mapping\Id;
|
||||
use Doctrine\ORM\Mapping\ManyToMany;
|
||||
use Doctrine\ORM\Mapping\ManyToOne;
|
||||
|
||||
#[Entity]
|
||||
class BookWithGenre
|
||||
{
|
||||
#[Id]
|
||||
#[GeneratedValue]
|
||||
#[Column]
|
||||
public int $id;
|
||||
|
||||
#[ManyToOne(targetEntity: Library::class, inversedBy: 'books')]
|
||||
public Library $library;
|
||||
|
||||
#[Column(enumType: BookGenre::class)]
|
||||
public BookGenre $genre;
|
||||
|
||||
#[ManyToMany(targetEntity: BookCategory::class, inversedBy: 'books')]
|
||||
public Collection $categories;
|
||||
|
||||
public function __construct(BookGenre $genre)
|
||||
{
|
||||
$this->genre = $genre;
|
||||
$this->categories = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,9 @@ use Doctrine\ORM\Mapping\Id;
|
||||
class Card
|
||||
{
|
||||
/**
|
||||
* @Id @GeneratedValue @Column(type="integer")
|
||||
* @Id
|
||||
* @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
#[Id]
|
||||
|
||||
@@ -15,7 +15,9 @@ use Doctrine\ORM\Mapping\Id;
|
||||
class CardWithNullable
|
||||
{
|
||||
/**
|
||||
* @Id @GeneratedValue @Column(type="integer")
|
||||
* @Id
|
||||
* @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
#[Id]
|
||||
|
||||
32
tests/Tests/Models/Enums/Library.php
Normal file
32
tests/Tests/Models/Enums/Library.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\Enums;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\GeneratedValue;
|
||||
use Doctrine\ORM\Mapping\Id;
|
||||
use Doctrine\ORM\Mapping\OneToMany;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
|
||||
#[Entity]
|
||||
#[Table('`library`')]
|
||||
class Library
|
||||
{
|
||||
#[Id]
|
||||
#[GeneratedValue]
|
||||
#[Column]
|
||||
public int $id;
|
||||
|
||||
#[OneToMany(targetEntity: BookWithGenre::class, mappedBy: 'library')]
|
||||
public Collection $books;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->books = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,9 @@ use Doctrine\ORM\Mapping\Id;
|
||||
class Scale
|
||||
{
|
||||
/**
|
||||
* @Id @GeneratedValue @Column(type="integer")
|
||||
* @Id
|
||||
* @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
#[Id]
|
||||
|
||||
@@ -19,8 +19,6 @@ class GH10336Relation
|
||||
*/
|
||||
public ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
/** @ORM\Column(type="string") */
|
||||
public string $value;
|
||||
}
|
||||
|
||||
@@ -29,9 +29,7 @@ class GH11524Relation
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
/** @var string|null */
|
||||
private $currentLocale;
|
||||
|
||||
public function setCurrentLocale(string $locale): void
|
||||
|
||||
@@ -19,8 +19,6 @@ class GH7717Child
|
||||
*/
|
||||
public ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", nullable=true)
|
||||
*/
|
||||
/** @ORM\Column(type="string", nullable=true) */
|
||||
public ?string $nullableProperty = null;
|
||||
}
|
||||
|
||||
@@ -6,14 +6,10 @@ namespace Doctrine\Tests\Models\Project;
|
||||
|
||||
class Project
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
public function __construct(string $id, string $name)
|
||||
|
||||
@@ -6,9 +6,7 @@ namespace Doctrine\Tests\Models\Project;
|
||||
|
||||
class ProjectId
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
private $id;
|
||||
|
||||
public function __construct(string $id)
|
||||
|
||||
@@ -6,14 +6,10 @@ namespace Doctrine\Tests\Models\Project;
|
||||
|
||||
class ProjectInvalidMapping
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
public function __construct(string $id, string $name)
|
||||
|
||||
@@ -6,9 +6,7 @@ namespace Doctrine\Tests\Models\Project;
|
||||
|
||||
final class ProjectName
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
public function __construct(string $name)
|
||||
|
||||
@@ -25,6 +25,12 @@ class InversedManyToManyEntity
|
||||
*/
|
||||
public $id1;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @Column(type="rot13", length=255, nullable=true)
|
||||
*/
|
||||
public $field = null;
|
||||
|
||||
/**
|
||||
* @phpstan-var Collection<int, OwningManyToManyEntity>
|
||||
* @ManyToMany(targetEntity="OwningManyToManyEntity", mappedBy="associatedEntities")
|
||||
|
||||
@@ -33,7 +33,7 @@ class InversedOneToManyEntity
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @Column(type="string", name="some_property", length=255)
|
||||
* @Column(type="string", name="some_property", length=255, nullable=true)
|
||||
*/
|
||||
public $someProperty;
|
||||
|
||||
|
||||
@@ -27,6 +27,12 @@ class OwningManyToManyEntity
|
||||
*/
|
||||
public $id2;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @Column(type="rot13", length=255, nullable=true)
|
||||
*/
|
||||
public $field = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, InversedManyToManyEntity>
|
||||
* @ManyToMany(targetEntity="InversedManyToManyEntity", inversedBy="associatedEntities")
|
||||
|
||||
@@ -24,6 +24,12 @@ class OwningManyToOneEntity
|
||||
*/
|
||||
public $id2;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @Column(type="rot13", length=255, nullable=true)
|
||||
*/
|
||||
public $field = null;
|
||||
|
||||
/**
|
||||
* @var InversedOneToManyEntity
|
||||
* @ManyToOne(targetEntity="InversedOneToManyEntity", inversedBy="associatedEntities")
|
||||
|
||||
@@ -27,9 +27,7 @@ final class AbstractQueryTest extends TestCase
|
||||
|
||||
$configuration = new Configuration();
|
||||
$configuration->setHydrationCache($cache);
|
||||
$entityManager = $this->createMock(EntityManagerInterface::class);
|
||||
$entityManager->method('getConfiguration')->willReturn($configuration);
|
||||
$query = $this->getMockForAbstractClass(AbstractQuery::class, [$entityManager]);
|
||||
$query = $this->createAbstractQuery($configuration);
|
||||
$cacheProfile = new QueryCacheProfile();
|
||||
|
||||
$query->setHydrationCacheProfile($cacheProfile);
|
||||
@@ -45,9 +43,7 @@ final class AbstractQueryTest extends TestCase
|
||||
|
||||
$configuration = new Configuration();
|
||||
$configuration->setHydrationCache($cache);
|
||||
$entityManager = $this->createMock(EntityManagerInterface::class);
|
||||
$entityManager->method('getConfiguration')->willReturn($configuration);
|
||||
$query = $this->getMockForAbstractClass(AbstractQuery::class, [$entityManager]);
|
||||
$query = $this->createAbstractQuery($configuration);
|
||||
$cacheProfile = new QueryCacheProfile();
|
||||
|
||||
$query->setHydrationCacheProfile($cacheProfile);
|
||||
@@ -61,9 +57,7 @@ final class AbstractQueryTest extends TestCase
|
||||
|
||||
$configuration = new Configuration();
|
||||
$configuration->setResultCache($cache);
|
||||
$entityManager = $this->createMock(EntityManagerInterface::class);
|
||||
$entityManager->method('getConfiguration')->willReturn($configuration);
|
||||
$query = $this->getMockForAbstractClass(AbstractQuery::class, [$entityManager]);
|
||||
$query = $this->createAbstractQuery($configuration);
|
||||
$cacheProfile = new QueryCacheProfile();
|
||||
|
||||
$query->setResultCacheProfile($cacheProfile);
|
||||
@@ -74,9 +68,7 @@ final class AbstractQueryTest extends TestCase
|
||||
/** @dataProvider provideSettersWithDeprecatedDefault */
|
||||
public function testCallingSettersWithoutArgumentsIsDeprecated(string $setter): void
|
||||
{
|
||||
$entityManager = $this->createMock(EntityManagerInterface::class);
|
||||
$entityManager->method('getConfiguration')->willReturn(new Configuration());
|
||||
$query = $this->getMockForAbstractClass(AbstractQuery::class, [$entityManager]);
|
||||
$query = $this->createAbstractQuery(new Configuration());
|
||||
|
||||
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/pull/9791');
|
||||
$query->$setter();
|
||||
@@ -95,10 +87,7 @@ final class AbstractQueryTest extends TestCase
|
||||
public function testSettingTheResultCacheIsPossibleWithoutCallingDeprecatedMethods(): void
|
||||
{
|
||||
$cache = $this->createMock(CacheItemPoolInterface::class);
|
||||
|
||||
$entityManager = $this->createMock(EntityManagerInterface::class);
|
||||
$entityManager->method('getConfiguration')->willReturn(new Configuration());
|
||||
$query = $this->getMockForAbstractClass(AbstractQuery::class, [$entityManager]);
|
||||
$query = $this->createAbstractQuery(new Configuration());
|
||||
|
||||
$query->setResultCache($cache);
|
||||
self::assertSame($cache, CacheAdapter::wrap($query->getResultCacheDriver()));
|
||||
@@ -107,13 +96,27 @@ final class AbstractQueryTest extends TestCase
|
||||
|
||||
public function testSettingTheFetchModeToRandomIntegersIsDeprecated(): void
|
||||
{
|
||||
$query = $this->getMockForAbstractClass(
|
||||
AbstractQuery::class,
|
||||
[],
|
||||
'',
|
||||
false // no need to call the constructor
|
||||
);
|
||||
$query = $this->createAbstractQuery(new Configuration());
|
||||
|
||||
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/pull/9777');
|
||||
$query->setFetchMode(stdClass::class, 'foo', 42);
|
||||
}
|
||||
|
||||
private function createAbstractQuery(Configuration $configuration): AbstractQuery
|
||||
{
|
||||
$entityManager = $this->createMock(EntityManagerInterface::class);
|
||||
$entityManager->method('getConfiguration')->willReturn($configuration);
|
||||
|
||||
return new class ($entityManager) extends AbstractQuery {
|
||||
public function getSQL(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function _doExecute(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ use ReflectionProperty;
|
||||
|
||||
use function array_merge;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/** @group DDC-2183 */
|
||||
class DefaultCacheTest extends OrmTestCase
|
||||
{
|
||||
@@ -244,8 +246,11 @@ class DefaultCacheTest extends OrmTestCase
|
||||
$method = new ReflectionMethod($this->cache, 'toIdentifierArray');
|
||||
$property = new ReflectionProperty($entity, 'id');
|
||||
|
||||
$property->setAccessible(true);
|
||||
$method->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
$method->setAccessible(true);
|
||||
}
|
||||
|
||||
$property->setValue($entity, $identifier);
|
||||
|
||||
self::assertEquals(['id' => $identifier], $method->invoke($this->cache, $metadata, $identifier));
|
||||
|
||||
@@ -30,6 +30,8 @@ use ReflectionMethod;
|
||||
use function microtime;
|
||||
use function sprintf;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/** @group DDC-2183 */
|
||||
class DefaultQueryCacheTest extends OrmTestCase
|
||||
{
|
||||
@@ -585,7 +587,9 @@ class DefaultQueryCacheTest extends OrmTestCase
|
||||
$rsm = new ResultSetMappingBuilder($this->em);
|
||||
$key = new QueryCacheKey('query.key1', 0);
|
||||
|
||||
$reflection->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$reflection->setAccessible(true);
|
||||
}
|
||||
|
||||
$germany = new Country('Germany');
|
||||
$bavaria = new State('Bavaria', $germany);
|
||||
|
||||
@@ -27,6 +27,7 @@ use function uniqid;
|
||||
use function unlink;
|
||||
|
||||
use const E_WARNING;
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/**
|
||||
* @extends RegionTestCase<FileLockRegion>
|
||||
@@ -46,7 +47,9 @@ class FileLockRegionTest extends RegionTestCase
|
||||
{
|
||||
$reflection = new ReflectionMethod($region, 'getLockFileName');
|
||||
|
||||
$reflection->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$reflection->setAccessible(true);
|
||||
}
|
||||
|
||||
return $reflection->invoke($region, $key);
|
||||
}
|
||||
@@ -227,7 +230,10 @@ class FileLockRegionTest extends RegionTestCase
|
||||
$file = $this->getFileName($this->region, $key);
|
||||
$property = new ReflectionProperty($this->region, 'lockLifetime');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$property->setValue($this->region, -10);
|
||||
|
||||
self::assertFalse($this->region->contains($key));
|
||||
@@ -253,7 +259,10 @@ class FileLockRegionTest extends RegionTestCase
|
||||
$region = $this->createRegion();
|
||||
$reflectionDirectory = new ReflectionProperty($region, 'directory');
|
||||
|
||||
$reflectionDirectory->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$reflectionDirectory->setAccessible(true);
|
||||
}
|
||||
|
||||
$reflectionDirectory->setValue($region, str_repeat('a', 10000));
|
||||
|
||||
set_error_handler(static function (): bool {
|
||||
|
||||
@@ -15,6 +15,8 @@ use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Doctrine\Tests\Models\Cache\State;
|
||||
use ReflectionProperty;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/** @group DDC-2183 */
|
||||
class ReadWriteCachedCollectionPersisterTest extends CollectionPersisterTestCase
|
||||
{
|
||||
@@ -121,7 +123,9 @@ class ReadWriteCachedCollectionPersisterTest extends CollectionPersisterTestCase
|
||||
$key = new CollectionCacheKey(State::class, 'cities', ['id' => 1]);
|
||||
$property = new ReflectionProperty(ReadWriteCachedCollectionPersister::class, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('lock')
|
||||
@@ -153,7 +157,9 @@ class ReadWriteCachedCollectionPersisterTest extends CollectionPersisterTestCase
|
||||
$key = new CollectionCacheKey(State::class, 'cities', ['id' => 1]);
|
||||
$property = new ReflectionProperty(ReadWriteCachedCollectionPersister::class, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('lock')
|
||||
@@ -185,7 +191,9 @@ class ReadWriteCachedCollectionPersisterTest extends CollectionPersisterTestCase
|
||||
$key = new CollectionCacheKey(State::class, 'cities', ['id' => 1]);
|
||||
$property = new ReflectionProperty(ReadWriteCachedCollectionPersister::class, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('lock')
|
||||
@@ -217,7 +225,9 @@ class ReadWriteCachedCollectionPersisterTest extends CollectionPersisterTestCase
|
||||
$key = new CollectionCacheKey(State::class, 'cities', ['id' => 1]);
|
||||
$property = new ReflectionProperty(ReadWriteCachedCollectionPersister::class, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('lock')
|
||||
@@ -248,7 +258,9 @@ class ReadWriteCachedCollectionPersisterTest extends CollectionPersisterTestCase
|
||||
$key = new CollectionCacheKey(State::class, 'cities', ['id' => 1]);
|
||||
$property = new ReflectionProperty(ReadWriteCachedCollectionPersister::class, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('lock')
|
||||
@@ -273,7 +285,9 @@ class ReadWriteCachedCollectionPersisterTest extends CollectionPersisterTestCase
|
||||
$key = new CollectionCacheKey(State::class, 'cities', ['id' => 1]);
|
||||
$property = new ReflectionProperty(ReadWriteCachedCollectionPersister::class, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('lock')
|
||||
|
||||
@@ -143,7 +143,7 @@ abstract class EntityPersisterTestCase extends OrmTestCase
|
||||
public function testInvokeExpandCriteriaParameters(): void
|
||||
{
|
||||
$persister = $this->createPersisterDefault();
|
||||
$criteria = new Criteria();
|
||||
$criteria = Criteria::create(true);
|
||||
|
||||
$this->entityPersister->expects(self::once())
|
||||
->method('expandCriteriaParameters')
|
||||
@@ -313,7 +313,7 @@ abstract class EntityPersisterTestCase extends OrmTestCase
|
||||
$rsm = new ResultSetMappingBuilder($this->em);
|
||||
$persister = $this->createPersisterDefault();
|
||||
$entity = new Country('Foo');
|
||||
$criteria = new Criteria();
|
||||
$criteria = Criteria::create(true);
|
||||
|
||||
$this->em->getUnitOfWork()->registerManaged($entity, ['id' => 1], ['id' => 1, 'name' => 'Foo']);
|
||||
$rsm->addEntityResult(Country::class, 'c');
|
||||
|
||||
@@ -15,6 +15,8 @@ use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use Doctrine\Tests\Models\Cache\Country;
|
||||
use ReflectionProperty;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/** @group DDC-2183 */
|
||||
class NonStrictReadWriteCachedEntityPersisterTest extends EntityPersisterTestCase
|
||||
{
|
||||
@@ -29,7 +31,9 @@ class NonStrictReadWriteCachedEntityPersisterTest extends EntityPersisterTestCas
|
||||
$persister = $this->createPersisterDefault();
|
||||
$property = new ReflectionProperty($persister, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->em->getUnitOfWork()->registerManaged($entity, ['id' => 1], ['id' => 1, 'name' => 'Foo']);
|
||||
|
||||
@@ -51,7 +55,9 @@ class NonStrictReadWriteCachedEntityPersisterTest extends EntityPersisterTestCas
|
||||
$entry = new EntityCacheEntry(Country::class, ['id' => 1, 'name' => 'Foo']);
|
||||
$property = new ReflectionProperty($persister, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('put')
|
||||
@@ -88,7 +94,9 @@ class NonStrictReadWriteCachedEntityPersisterTest extends EntityPersisterTestCas
|
||||
$entry = new EntityCacheEntry(Country::class, ['id' => 1, 'name' => 'Foo']);
|
||||
$property = new ReflectionProperty($persister, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('put')
|
||||
@@ -116,7 +124,9 @@ class NonStrictReadWriteCachedEntityPersisterTest extends EntityPersisterTestCas
|
||||
$key = new EntityCacheKey(Country::class, ['id' => 1]);
|
||||
$property = new ReflectionProperty($persister, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('evict')
|
||||
|
||||
@@ -16,6 +16,8 @@ use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use Doctrine\Tests\Models\Cache\Country;
|
||||
use ReflectionProperty;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/** @group DDC-2183 */
|
||||
class ReadWriteCachedEntityPersisterTest extends EntityPersisterTestCase
|
||||
{
|
||||
@@ -116,7 +118,9 @@ class ReadWriteCachedEntityPersisterTest extends EntityPersisterTestCase
|
||||
$key = new EntityCacheKey(Country::class, ['id' => 1]);
|
||||
$property = new ReflectionProperty(ReadWriteCachedEntityPersister::class, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::exactly(2))
|
||||
->method('lock')
|
||||
@@ -147,7 +151,9 @@ class ReadWriteCachedEntityPersisterTest extends EntityPersisterTestCase
|
||||
$key = new EntityCacheKey(Country::class, ['id' => 1]);
|
||||
$property = new ReflectionProperty(ReadWriteCachedEntityPersister::class, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::exactly(2))
|
||||
->method('lock')
|
||||
@@ -177,7 +183,9 @@ class ReadWriteCachedEntityPersisterTest extends EntityPersisterTestCase
|
||||
$key = new EntityCacheKey(Country::class, ['id' => 1]);
|
||||
$property = new ReflectionProperty(ReadWriteCachedEntityPersister::class, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('lock')
|
||||
@@ -201,7 +209,9 @@ class ReadWriteCachedEntityPersisterTest extends EntityPersisterTestCase
|
||||
$key = new EntityCacheKey(Country::class, ['id' => 1]);
|
||||
$property = new ReflectionProperty(ReadWriteCachedEntityPersister::class, 'queuedCache');
|
||||
|
||||
$property->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$property->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->region->expects(self::once())
|
||||
->method('lock')
|
||||
|
||||
@@ -494,13 +494,13 @@ class ClassTableInheritanceTest extends OrmFunctionalTestCase
|
||||
$this->_em->flush();
|
||||
|
||||
$repository = $this->_em->getRepository(CompanyEmployee::class);
|
||||
$users = $repository->matching(new Criteria(
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('department', 'IT')
|
||||
));
|
||||
self::assertCount(1, $users);
|
||||
|
||||
$repository = $this->_em->getRepository(CompanyManager::class);
|
||||
$users = $repository->matching(new Criteria(
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('department', 'IT')
|
||||
));
|
||||
self::assertCount(1, $users);
|
||||
|
||||
@@ -66,7 +66,7 @@ class EntityRepositoryCriteriaTest extends OrmFunctionalTestCase
|
||||
$this->loadFixture();
|
||||
|
||||
$repository = $this->_em->getRepository(DateTimeModel::class);
|
||||
$dates = $repository->matching(new Criteria(
|
||||
$dates = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->lte('datetime', new DateTime('today'))
|
||||
));
|
||||
|
||||
@@ -98,7 +98,7 @@ class EntityRepositoryCriteriaTest extends OrmFunctionalTestCase
|
||||
$this->loadNullFieldFixtures();
|
||||
$repository = $this->_em->getRepository(DateTimeModel::class);
|
||||
|
||||
$dates = $repository->matching(new Criteria(
|
||||
$dates = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->isNull('time')
|
||||
));
|
||||
|
||||
@@ -110,7 +110,7 @@ class EntityRepositoryCriteriaTest extends OrmFunctionalTestCase
|
||||
$this->loadNullFieldFixtures();
|
||||
$repository = $this->_em->getRepository(DateTimeModel::class);
|
||||
|
||||
$dates = $repository->matching(new Criteria(
|
||||
$dates = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('time', null)
|
||||
));
|
||||
|
||||
@@ -122,7 +122,7 @@ class EntityRepositoryCriteriaTest extends OrmFunctionalTestCase
|
||||
$this->loadNullFieldFixtures();
|
||||
$repository = $this->_em->getRepository(DateTimeModel::class);
|
||||
|
||||
$dates = $repository->matching(new Criteria(
|
||||
$dates = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->neq('time', null)
|
||||
));
|
||||
|
||||
@@ -134,14 +134,14 @@ class EntityRepositoryCriteriaTest extends OrmFunctionalTestCase
|
||||
$this->loadFixture();
|
||||
$repository = $this->_em->getRepository(DateTimeModel::class);
|
||||
|
||||
$dates = $repository->matching(new Criteria());
|
||||
$dates = $repository->matching(Criteria::create(true));
|
||||
|
||||
self::assertFalse($dates->isInitialized());
|
||||
self::assertCount(3, $dates);
|
||||
self::assertFalse($dates->isInitialized());
|
||||
|
||||
// Test it can work even with a constraint
|
||||
$dates = $repository->matching(new Criteria(
|
||||
$dates = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->lte('datetime', new DateTime('today'))
|
||||
));
|
||||
|
||||
@@ -169,7 +169,7 @@ class EntityRepositoryCriteriaTest extends OrmFunctionalTestCase
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$criteria = new Criteria();
|
||||
$criteria = Criteria::create(true);
|
||||
$criteria->andWhere($criteria->expr()->contains('content', 'Criteria'));
|
||||
|
||||
$user = $this->_em->find(User::class, $user->id);
|
||||
|
||||
@@ -734,7 +734,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$this->loadFixture();
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$users = $repository->matching(new Criteria());
|
||||
$users = $repository->matching(Criteria::create(true));
|
||||
|
||||
self::assertCount(4, $users);
|
||||
}
|
||||
@@ -745,7 +745,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$this->loadFixture();
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$users = $repository->matching(new Criteria(
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('username', 'beberlei')
|
||||
));
|
||||
|
||||
@@ -758,7 +758,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$this->loadFixture();
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$users = $repository->matching(new Criteria(
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->neq('username', 'beberlei')
|
||||
));
|
||||
|
||||
@@ -771,7 +771,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$this->loadFixture();
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$users = $repository->matching(new Criteria(
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->in('username', ['beberlei', 'gblanco'])
|
||||
));
|
||||
|
||||
@@ -784,7 +784,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$this->loadFixture();
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$users = $repository->matching(new Criteria(
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->notIn('username', ['beberlei', 'gblanco', 'asm89'])
|
||||
));
|
||||
|
||||
@@ -797,7 +797,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$firstUserId = $this->loadFixture();
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$users = $repository->matching(new Criteria(
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->lt('id', $firstUserId + 1)
|
||||
));
|
||||
|
||||
@@ -810,7 +810,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$firstUserId = $this->loadFixture();
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$users = $repository->matching(new Criteria(
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->lte('id', $firstUserId + 1)
|
||||
));
|
||||
|
||||
@@ -823,7 +823,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$firstUserId = $this->loadFixture();
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$users = $repository->matching(new Criteria(
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->gt('id', $firstUserId)
|
||||
));
|
||||
|
||||
@@ -836,7 +836,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$firstUserId = $this->loadFixture();
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$users = $repository->matching(new Criteria(
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->gte('id', $firstUserId)
|
||||
));
|
||||
|
||||
@@ -850,7 +850,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
|
||||
$user = $this->_em->find(CmsUser::class, $userId);
|
||||
|
||||
$criteria = new Criteria(
|
||||
$criteria = Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('user', $user)
|
||||
);
|
||||
|
||||
@@ -871,7 +871,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
|
||||
$user = $this->_em->find(CmsUser::class, $userId);
|
||||
|
||||
$criteria = new Criteria(
|
||||
$criteria = Criteria::create(true)->where(
|
||||
Criteria::expr()->in('user', [$user])
|
||||
);
|
||||
|
||||
@@ -891,13 +891,13 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
|
||||
$users = $repository->matching(new Criteria(Criteria::expr()->contains('name', 'Foobar')));
|
||||
$users = $repository->matching(Criteria::create(true)->where(Criteria::expr()->contains('name', 'Foobar')));
|
||||
self::assertCount(0, $users);
|
||||
|
||||
$users = $repository->matching(new Criteria(Criteria::expr()->contains('name', 'Rom')));
|
||||
$users = $repository->matching(Criteria::create(true)->where(Criteria::expr()->contains('name', 'Rom')));
|
||||
self::assertCount(1, $users);
|
||||
|
||||
$users = $repository->matching(new Criteria(Criteria::expr()->contains('status', 'dev')));
|
||||
$users = $repository->matching(Criteria::create(true)->where(Criteria::expr()->contains('status', 'dev')));
|
||||
self::assertCount(2, $users);
|
||||
}
|
||||
|
||||
@@ -907,13 +907,19 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
|
||||
$users = $repository->matching(new Criteria(Criteria::expr()->startsWith('name', 'Foo')));
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->startsWith('name', 'Foo')
|
||||
));
|
||||
self::assertCount(0, $users);
|
||||
|
||||
$users = $repository->matching(new Criteria(Criteria::expr()->startsWith('name', 'R')));
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->startsWith('name', 'R')
|
||||
));
|
||||
self::assertCount(1, $users);
|
||||
|
||||
$users = $repository->matching(new Criteria(Criteria::expr()->startsWith('status', 'de')));
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->startsWith('status', 'de')
|
||||
));
|
||||
self::assertCount(2, $users);
|
||||
}
|
||||
|
||||
@@ -923,13 +929,19 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
|
||||
$users = $repository->matching(new Criteria(Criteria::expr()->endsWith('name', 'foo')));
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->endsWith('name', 'foo')
|
||||
));
|
||||
self::assertCount(0, $users);
|
||||
|
||||
$users = $repository->matching(new Criteria(Criteria::expr()->endsWith('name', 'oman')));
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->endsWith('name', 'oman')
|
||||
));
|
||||
self::assertCount(1, $users);
|
||||
|
||||
$users = $repository->matching(new Criteria(Criteria::expr()->endsWith('status', 'ev')));
|
||||
$users = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->endsWith('status', 'ev')
|
||||
));
|
||||
self::assertCount(2, $users);
|
||||
}
|
||||
|
||||
@@ -939,8 +951,8 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$fixtures = $this->loadFixtureUserEmail();
|
||||
$user = $this->_em->find(CmsUser::class, $fixtures[0]->id);
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$criteriaIsNull = Criteria::create()->where(Criteria::expr()->isNull('email'));
|
||||
$criteriaEqNull = Criteria::create()->where(Criteria::expr()->eq('email', null));
|
||||
$criteriaIsNull = Criteria::create(true)->where(Criteria::expr()->isNull('email'));
|
||||
$criteriaEqNull = Criteria::create(true)->where(Criteria::expr()->eq('email', null));
|
||||
|
||||
$user->setEmail(null);
|
||||
$this->_em->persist($user);
|
||||
@@ -997,7 +1009,7 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
|
||||
$this->expectExceptionMessage('Unrecognized field: ');
|
||||
|
||||
$repository = $this->_em->getRepository(CmsUser::class);
|
||||
$result = $repository->matching(new Criteria(
|
||||
$result = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('username = ?; DELETE FROM cms_users; SELECT 1 WHERE 1', 'beberlei')
|
||||
));
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\Expr\Comparison;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
|
||||
@@ -12,9 +14,13 @@ use Doctrine\ORM\Query\Expr\Func;
|
||||
use Doctrine\ORM\Tools\SchemaTool;
|
||||
use Doctrine\Tests\Models\DataTransferObjects\DtoWithArrayOfEnums;
|
||||
use Doctrine\Tests\Models\DataTransferObjects\DtoWithEnum;
|
||||
use Doctrine\Tests\Models\Enums\BookCategory;
|
||||
use Doctrine\Tests\Models\Enums\BookGenre;
|
||||
use Doctrine\Tests\Models\Enums\BookWithGenre;
|
||||
use Doctrine\Tests\Models\Enums\Card;
|
||||
use Doctrine\Tests\Models\Enums\CardWithDefault;
|
||||
use Doctrine\Tests\Models\Enums\CardWithNullable;
|
||||
use Doctrine\Tests\Models\Enums\Library;
|
||||
use Doctrine\Tests\Models\Enums\Product;
|
||||
use Doctrine\Tests\Models\Enums\Quantity;
|
||||
use Doctrine\Tests\Models\Enums\Scale;
|
||||
@@ -22,6 +28,7 @@ use Doctrine\Tests\Models\Enums\Suit;
|
||||
use Doctrine\Tests\Models\Enums\TypedCard;
|
||||
use Doctrine\Tests\Models\Enums\Unit;
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use Generator;
|
||||
|
||||
use function dirname;
|
||||
use function sprintf;
|
||||
@@ -524,4 +531,72 @@ EXCEPTION
|
||||
|
||||
self::assertSame(Suit::Hearts, $card->suit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGenreMatchingExpressions
|
||||
*/
|
||||
public function testEnumCollectionMatchingOnOneToMany(Comparison $comparison): void
|
||||
{
|
||||
$this->setUpEntitySchema([BookWithGenre::class, Library::class, BookCategory::class]);
|
||||
|
||||
$library = new Library();
|
||||
|
||||
$fictionBook = new BookWithGenre(BookGenre::FICTION);
|
||||
$fictionBook->library = $library;
|
||||
|
||||
$nonfictionBook = new BookWithGenre(BookGenre::NON_FICTION);
|
||||
$nonfictionBook->library = $library;
|
||||
|
||||
$this->_em->persist($library);
|
||||
$this->_em->persist($nonfictionBook);
|
||||
$this->_em->persist($fictionBook);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$library = $this->_em->find(Library::class, $library->id);
|
||||
self::assertFalse($library->books->isInitialized(), 'Pre-condition: lazy collection');
|
||||
|
||||
$result = $library->books->matching(Criteria::create(true)->where($comparison));
|
||||
|
||||
self::assertCount(1, $result);
|
||||
self::assertSame($nonfictionBook->id, $result[0]->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGenreMatchingExpressions
|
||||
*/
|
||||
public function testEnumCollectionMatchingOnManyToMany(Comparison $comparison): void
|
||||
{
|
||||
$this->setUpEntitySchema([Library::class, BookWithGenre::class, BookCategory::class]);
|
||||
|
||||
$category = new BookCategory();
|
||||
|
||||
$fictionBook = new BookWithGenre(BookGenre::FICTION);
|
||||
$fictionBook->categories->add($category);
|
||||
|
||||
$nonfictionBook = new BookWithGenre(BookGenre::NON_FICTION);
|
||||
$nonfictionBook->categories->add($category);
|
||||
|
||||
$this->_em->persist($category);
|
||||
$this->_em->persist($nonfictionBook);
|
||||
$this->_em->persist($fictionBook);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$category = $this->_em->find(BookCategory::class, $category->id);
|
||||
self::assertFalse($category->books->isInitialized(), 'Pre-condition: lazy collection');
|
||||
|
||||
$result = $category->books->matching(Criteria::create(true)->where($comparison));
|
||||
|
||||
self::assertCount(1, $result);
|
||||
self::assertSame($nonfictionBook->id, $result[0]->id);
|
||||
}
|
||||
|
||||
public function provideGenreMatchingExpressions(): Generator
|
||||
{
|
||||
yield [Criteria::expr()->eq('genre', BookGenre::NON_FICTION)];
|
||||
yield [Criteria::expr()->in('genre', [BookGenre::NON_FICTION])];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,7 +437,7 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
|
||||
|
||||
$user = $this->_em->find(get_class($user), $user->id);
|
||||
|
||||
$criteria = Criteria::create()
|
||||
$criteria = Criteria::create(true)
|
||||
->orderBy(['name' => class_exists(Order::class) ? Order::Ascending : Criteria::ASC]);
|
||||
|
||||
self::assertEquals(
|
||||
@@ -479,7 +479,7 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
|
||||
|
||||
$user = $this->_em->find(get_class($user), $user->id);
|
||||
|
||||
$criteria = Criteria::create()
|
||||
$criteria = Criteria::create(true)
|
||||
->orderBy(['name' => class_exists(Order::class) ? Order::Ascending : Criteria::ASC]);
|
||||
|
||||
self::assertEquals(
|
||||
@@ -504,7 +504,7 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
|
||||
$groups = $user->groups;
|
||||
self::assertFalse($user->groups->isInitialized(), 'Pre-condition: lazy collection');
|
||||
|
||||
$criteria = Criteria::create()->setMaxResults(1);
|
||||
$criteria = Criteria::create(true)->setMaxResults(1);
|
||||
$result = $groups->matching($criteria);
|
||||
|
||||
self::assertCount(1, $result);
|
||||
@@ -522,7 +522,7 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
|
||||
$groups = $user->groups;
|
||||
self::assertFalse($user->groups->isInitialized(), 'Pre-condition: lazy collection');
|
||||
|
||||
$criteria = Criteria::create()->setFirstResult(1);
|
||||
$criteria = Criteria::create(true)->setFirstResult(1);
|
||||
$result = $groups->matching($criteria);
|
||||
|
||||
self::assertCount(1, $result);
|
||||
@@ -543,7 +543,7 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
|
||||
$groups = $user->groups;
|
||||
self::assertFalse($user->groups->isInitialized(), 'Pre-condition: lazy collection');
|
||||
|
||||
$criteria = Criteria::create()->setFirstResult(1)->setMaxResults(3);
|
||||
$criteria = Criteria::create(true)->setFirstResult(1)->setMaxResults(3);
|
||||
$result = $groups->matching($criteria);
|
||||
|
||||
self::assertCount(3, $result);
|
||||
@@ -567,7 +567,7 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
|
||||
$groups = $user->groups;
|
||||
self::assertFalse($user->groups->isInitialized(), 'Pre-condition: lazy collection');
|
||||
|
||||
$criteria = Criteria::create()->where(Criteria::expr()->eq('name', (string) 'Developers_0'));
|
||||
$criteria = Criteria::create(true)->where(Criteria::expr()->eq('name', (string) 'Developers_0'));
|
||||
$result = $groups->matching($criteria);
|
||||
|
||||
self::assertCount(1, $result);
|
||||
@@ -578,6 +578,44 @@ class ManyToManyBasicAssociationTest extends OrmFunctionalTestCase
|
||||
self::assertFalse($user->groups->isInitialized(), 'Post-condition: matching does not initialize collection');
|
||||
}
|
||||
|
||||
public function testMatchingWithInCondition(): void
|
||||
{
|
||||
$user = $this->addCmsUserGblancoWithGroups(2);
|
||||
$this->_em->clear();
|
||||
|
||||
$user = $this->_em->find(get_class($user), $user->id);
|
||||
|
||||
$groups = $user->groups;
|
||||
self::assertFalse($user->groups->isInitialized(), 'Pre-condition: lazy collection');
|
||||
|
||||
$criteria = Criteria::create(true)->where(Criteria::expr()->in('name', ['Developers_1']));
|
||||
$result = $groups->matching($criteria);
|
||||
|
||||
self::assertCount(1, $result);
|
||||
self::assertEquals('Developers_1', $result[0]->name);
|
||||
|
||||
self::assertFalse($user->groups->isInitialized(), 'Post-condition: matching does not initialize collection');
|
||||
}
|
||||
|
||||
public function testMatchingWithNotInCondition(): void
|
||||
{
|
||||
$user = $this->addCmsUserGblancoWithGroups(2);
|
||||
$this->_em->clear();
|
||||
|
||||
$user = $this->_em->find(get_class($user), $user->id);
|
||||
|
||||
$groups = $user->groups;
|
||||
self::assertFalse($user->groups->isInitialized(), 'Pre-condition: lazy collection');
|
||||
|
||||
$criteria = Criteria::create(true)->where(Criteria::expr()->notIn('name', ['Developers_0']));
|
||||
$result = $groups->matching($criteria);
|
||||
|
||||
self::assertCount(1, $result);
|
||||
self::assertEquals('Developers_1', $result[0]->name);
|
||||
|
||||
self::assertFalse($user->groups->isInitialized(), 'Post-condition: matching does not initialize collection');
|
||||
}
|
||||
|
||||
private function removeTransactionCommandsFromQueryLog(): void
|
||||
{
|
||||
$log = $this->getQueryLog();
|
||||
|
||||
@@ -166,14 +166,14 @@ class OneToManyBidirectionalAssociationTest extends OrmFunctionalTestCase
|
||||
$product = $this->_em->find(ECommerceProduct::class, $this->product->getId());
|
||||
$features = $product->getFeatures();
|
||||
|
||||
$results = $features->matching(new Criteria(
|
||||
$results = $features->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('description', 'Model writing tutorial')
|
||||
));
|
||||
|
||||
self::assertInstanceOf(Collection::class, $results);
|
||||
self::assertCount(1, $results);
|
||||
|
||||
$results = $features->matching(new Criteria());
|
||||
$results = $features->matching(Criteria::create(true));
|
||||
|
||||
self::assertInstanceOf(Collection::class, $results);
|
||||
self::assertCount(2, $results);
|
||||
@@ -192,7 +192,7 @@ class OneToManyBidirectionalAssociationTest extends OrmFunctionalTestCase
|
||||
$features = $product->getFeatures();
|
||||
$features->add($thirdFeature);
|
||||
|
||||
$results = $features->matching(new Criteria(
|
||||
$results = $features->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('description', 'Model writing tutorial')
|
||||
));
|
||||
|
||||
@@ -210,14 +210,14 @@ class OneToManyBidirectionalAssociationTest extends OrmFunctionalTestCase
|
||||
$thirdFeature->setDescription('Third feature');
|
||||
$product->addFeature($thirdFeature);
|
||||
|
||||
$results = $features->matching(new Criteria(
|
||||
$results = $features->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('description', 'Third feature')
|
||||
));
|
||||
|
||||
self::assertInstanceOf(Collection::class, $results);
|
||||
self::assertCount(1, $results);
|
||||
|
||||
$results = $features->matching(new Criteria());
|
||||
$results = $features->matching(Criteria::create(true));
|
||||
|
||||
self::assertInstanceOf(Collection::class, $results);
|
||||
self::assertCount(3, $results);
|
||||
|
||||
@@ -27,6 +27,8 @@ use function count;
|
||||
use function iterator_to_array;
|
||||
use function sprintf;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/** @group DDC-1613 */
|
||||
class PaginationTest extends OrmFunctionalTestCase
|
||||
{
|
||||
@@ -630,7 +632,9 @@ class PaginationTest extends OrmFunctionalTestCase
|
||||
|
||||
$getCountQuery = new ReflectionMethod($paginator, 'getCountQuery');
|
||||
|
||||
$getCountQuery->setAccessible(true);
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$getCountQuery->setAccessible(true);
|
||||
}
|
||||
|
||||
self::assertCount(2, $getCountQuery->invoke($paginator)->getParameters());
|
||||
self::assertCount(9, $paginator);
|
||||
|
||||
@@ -23,6 +23,8 @@ use function rtrim;
|
||||
use function serialize;
|
||||
use function unserialize;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
class ParserResultSerializationTest extends OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
@@ -112,7 +114,10 @@ class ParserResultSerializationTest extends OrmFunctionalTestCase
|
||||
$unserialized = unserialize($serialized);
|
||||
|
||||
$r = new ReflectionProperty($unserialized->getSqlExecutor(), '_sqlStatements');
|
||||
$r->setAccessible(true);
|
||||
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$r->setAccessible(true);
|
||||
}
|
||||
|
||||
$this->assertSame(
|
||||
$r->getValue($unserialized->getSqlExecutor()),
|
||||
@@ -166,7 +171,10 @@ class ParserResultSerializationTest extends OrmFunctionalTestCase
|
||||
private static function parseQuery(Query $query): ParserResult
|
||||
{
|
||||
$r = new ReflectionMethod($query, 'parse');
|
||||
$r->setAccessible(true);
|
||||
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$r->setAccessible(true);
|
||||
}
|
||||
|
||||
return $r->invoke($query);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ class PersistentCollectionCriteriaTest extends OrmFunctionalTestCase
|
||||
$repository = $this->_em->getRepository(User::class);
|
||||
|
||||
$user = $repository->findOneBy(['name' => 'ngal']);
|
||||
$tweets = $user->tweets->matching(new Criteria());
|
||||
$tweets = $user->tweets->matching(Criteria::create(true));
|
||||
|
||||
self::assertInstanceOf(LazyCriteriaCollection::class, $tweets);
|
||||
self::assertFalse($tweets->isInitialized());
|
||||
@@ -88,7 +88,7 @@ class PersistentCollectionCriteriaTest extends OrmFunctionalTestCase
|
||||
self::assertFalse($tweets->isInitialized());
|
||||
|
||||
// Make sure it works with constraints
|
||||
$tweets = $user->tweets->matching(new Criteria(
|
||||
$tweets = $user->tweets->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('content', 'Foo')
|
||||
));
|
||||
|
||||
@@ -117,7 +117,7 @@ class PersistentCollectionCriteriaTest extends OrmFunctionalTestCase
|
||||
|
||||
$parent = $this->_em->find(OwningManyToManyExtraLazyEntity::class, $parent->id2);
|
||||
|
||||
$criteria = Criteria::create()->where(Criteria::expr()->eq('id1', 'Bob'));
|
||||
$criteria = Criteria::create(true)->where(Criteria::expr()->eq('id1', 'Bob'));
|
||||
|
||||
$result = $parent->associatedEntities->matching($criteria);
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class PersistentCollectionTest extends OrmFunctionalTestCase
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$criteria = new Criteria();
|
||||
$criteria = Criteria::create(true);
|
||||
|
||||
$collectionHolder = $this->_em->find(PersistentCollectionHolder::class, $collectionHolder->getId());
|
||||
$collectionHolder->getCollection()->matching($criteria);
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
|
||||
use Doctrine\ORM\Query\ParserResult;
|
||||
@@ -121,15 +122,15 @@ class QueryCacheTest extends OrmFunctionalTestCase
|
||||
|
||||
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
|
||||
|
||||
$sqlExecMock = $this->getMockBuilder(AbstractSqlExecutor::class)
|
||||
->getMockForAbstractClass();
|
||||
|
||||
$sqlExecMock->expects(self::once())
|
||||
->method('execute')
|
||||
->willReturn(10);
|
||||
$sqlExecutorStub = new class extends AbstractSqlExecutor {
|
||||
public function execute(Connection $conn, array $params, array $types): int
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
};
|
||||
|
||||
$parserResultMock = new ParserResult();
|
||||
$parserResultMock->setSqlExecutor($sqlExecMock);
|
||||
$parserResultMock->setSqlExecutor($sqlExecutorStub);
|
||||
|
||||
$cache = $this->createMock(CacheItemPoolInterface::class);
|
||||
|
||||
|
||||
@@ -401,13 +401,128 @@ class QueryTest extends OrmFunctionalTestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testToIterableWithMixedResultIsNotAllowed(): void
|
||||
public function testToIterableWithMixedResultEntityScalars(): void
|
||||
{
|
||||
$this->expectException(QueryException::class);
|
||||
$this->expectExceptionMessage('Iterating a query with mixed results (using scalars) is not supported.');
|
||||
$author = new CmsUser();
|
||||
$author->name = 'Ben';
|
||||
$author->username = 'beberlei';
|
||||
|
||||
$query = $this->_em->createQuery('select a, a.topic from ' . CmsArticle::class . ' a');
|
||||
$query->toIterable();
|
||||
$article1 = new CmsArticle();
|
||||
$article1->topic = 'Doctrine 2';
|
||||
$article1->text = 'This is an introduction to Doctrine 2.';
|
||||
$article1->setAuthor($author);
|
||||
|
||||
$article2 = new CmsArticle();
|
||||
$article2->topic = 'Symfony 2';
|
||||
$article2->text = 'This is an introduction to Symfony 2.';
|
||||
$article2->setAuthor($author);
|
||||
|
||||
$article3 = new CmsArticle();
|
||||
$article3->topic = 'lala 2';
|
||||
$article3->text = 'This is an introduction to Symfony 2.';
|
||||
$article3->setAuthor($author);
|
||||
|
||||
$this->_em->persist($article1);
|
||||
$this->_em->persist($article2);
|
||||
$this->_em->persist($article3);
|
||||
$this->_em->persist($author);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery('select a, a.topic, a.text from ' . CmsArticle::class . ' a');
|
||||
$result = $query->toIterable();
|
||||
|
||||
$it = iterator_to_array($result);
|
||||
$this->assertCount(3, $it);
|
||||
$this->assertEquals('Doctrine 2', $it[0]['topic']);
|
||||
$this->assertEquals('Doctrine 2', $it[0][0]->topic);
|
||||
$this->assertEquals('lala 2', $it[2]['topic']);
|
||||
$this->assertEquals('lala 2', $it[2][0]->topic);
|
||||
}
|
||||
|
||||
public function testToIterableWithMixedResultArbitraryJoinsScalars(): void
|
||||
{
|
||||
$author = new CmsUser();
|
||||
$author->name = 'Ben';
|
||||
$author->username = 'beberlei';
|
||||
|
||||
$article1 = new CmsArticle();
|
||||
$article1->topic = 'Doctrine 2';
|
||||
$article1->text = 'This is an introduction to Doctrine 2.';
|
||||
$article1->setAuthor($author);
|
||||
|
||||
$article2 = new CmsArticle();
|
||||
$article2->topic = 'Symfony 2';
|
||||
$article2->text = 'This is an introduction to Symfony 2.';
|
||||
$article2->setAuthor($author);
|
||||
|
||||
$article3 = new CmsArticle();
|
||||
$article3->topic = 'lala 2';
|
||||
$article3->text = 'This is an introduction to Symfony 2.';
|
||||
$article3->setAuthor($author);
|
||||
|
||||
$this->_em->persist($article1);
|
||||
$this->_em->persist($article2);
|
||||
$this->_em->persist($article3);
|
||||
$this->_em->persist($author);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery('select a, u, a.topic, a.text from ' . CmsArticle::class . ' a, ' . CmsUser::class . ' u WHERE a.user = u ');
|
||||
$result = $query->toIterable();
|
||||
|
||||
$it = iterator_to_array($result);
|
||||
|
||||
$this->assertCount(3, $it);
|
||||
$this->assertEquals('Doctrine 2', $it[0]['topic']);
|
||||
$this->assertEquals('Doctrine 2', $it[0][0]->topic);
|
||||
$this->assertEquals('beberlei', $it[0][1]->username);
|
||||
$this->assertEquals('lala 2', $it[2]['topic']);
|
||||
$this->assertEquals('lala 2', $it[2][0]->topic);
|
||||
$this->assertEquals('beberlei', $it[2][1]->username);
|
||||
}
|
||||
|
||||
public function testToIterableWithMixedResultScalarsOnly(): void
|
||||
{
|
||||
$author = new CmsUser();
|
||||
$author->name = 'Ben';
|
||||
$author->username = 'beberlei';
|
||||
|
||||
$article1 = new CmsArticle();
|
||||
$article1->topic = 'Doctrine 2';
|
||||
$article1->text = 'This is an introduction to Doctrine 2.';
|
||||
$article1->setAuthor($author);
|
||||
|
||||
$article2 = new CmsArticle();
|
||||
$article2->topic = 'Symfony 2';
|
||||
$article2->text = 'This is an introduction to Symfony 2.';
|
||||
$article2->setAuthor($author);
|
||||
|
||||
$article3 = new CmsArticle();
|
||||
$article3->topic = 'lala 2';
|
||||
$article3->text = 'This is an introduction to Symfony 2.';
|
||||
$article3->setAuthor($author);
|
||||
|
||||
$this->_em->persist($article1);
|
||||
$this->_em->persist($article2);
|
||||
$this->_em->persist($article3);
|
||||
$this->_em->persist($author);
|
||||
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$query = $this->_em->createQuery('select a.topic, a.text from ' . CmsArticle::class . ' a ');
|
||||
$result = $query->toIterable();
|
||||
|
||||
$it = iterator_to_array($result);
|
||||
|
||||
$this->assertEquals([
|
||||
['topic' => 'Doctrine 2', 'text' => 'This is an introduction to Doctrine 2.'],
|
||||
['topic' => 'Symfony 2', 'text' => 'This is an introduction to Symfony 2.'],
|
||||
['topic' => 'lala 2', 'text' => 'This is an introduction to Symfony 2.'],
|
||||
], $it);
|
||||
}
|
||||
|
||||
public function testIterateResultClearEveryCycle(): void
|
||||
|
||||
@@ -35,6 +35,8 @@ use function count;
|
||||
use function in_array;
|
||||
use function serialize;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/**
|
||||
* Tests SQLFilter functionality.
|
||||
*
|
||||
@@ -303,7 +305,10 @@ class SQLFilterTest extends OrmFunctionalTestCase
|
||||
$filter = new MyLocaleFilter($em);
|
||||
|
||||
$reflMethod = new ReflectionMethod(SQLFilter::class, 'getConnection');
|
||||
$reflMethod->setAccessible(true);
|
||||
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$reflMethod->setAccessible(true);
|
||||
}
|
||||
|
||||
self::assertSame($conn, $reflMethod->invoke($filter));
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use function strpos;
|
||||
use function sys_get_temp_dir;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/**
|
||||
* @group DDC-2183
|
||||
@@ -49,7 +50,11 @@ class SecondLevelCacheCountQueriesTest extends SecondLevelCacheFunctionalTestCas
|
||||
|
||||
if ($cacheUsage === 0) {
|
||||
$metadataCacheReflection = new ReflectionProperty(ClassMetadataInfo::class, 'cache');
|
||||
$metadataCacheReflection->setAccessible(true);
|
||||
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$metadataCacheReflection->setAccessible(true);
|
||||
}
|
||||
|
||||
$metadataCacheReflection->setValue($metadata, null);
|
||||
|
||||
return;
|
||||
|
||||
@@ -25,7 +25,7 @@ class SecondLevelCacheCriteriaTest extends SecondLevelCacheFunctionalTestCase
|
||||
$repository = $this->_em->getRepository(Country::class);
|
||||
$this->getQueryLog()->reset()->enable();
|
||||
$name = $this->countries[0]->getName();
|
||||
$result1 = $repository->matching(new Criteria(
|
||||
$result1 = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('name', $name)
|
||||
));
|
||||
|
||||
@@ -40,7 +40,7 @@ class SecondLevelCacheCriteriaTest extends SecondLevelCacheFunctionalTestCase
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$result2 = $repository->matching(new Criteria(
|
||||
$result2 = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('name', $name)
|
||||
));
|
||||
|
||||
@@ -64,7 +64,7 @@ class SecondLevelCacheCriteriaTest extends SecondLevelCacheFunctionalTestCase
|
||||
|
||||
$repository = $this->_em->getRepository(Country::class);
|
||||
$this->getQueryLog()->reset()->enable();
|
||||
$result1 = $repository->matching(new Criteria(
|
||||
$result1 = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('name', $this->countries[0]->getName())
|
||||
));
|
||||
|
||||
@@ -78,7 +78,7 @@ class SecondLevelCacheCriteriaTest extends SecondLevelCacheFunctionalTestCase
|
||||
|
||||
$this->_em->clear();
|
||||
|
||||
$result2 = $repository->matching(new Criteria(
|
||||
$result2 = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('name', $this->countries[0]->getName())
|
||||
));
|
||||
|
||||
@@ -93,7 +93,7 @@ class SecondLevelCacheCriteriaTest extends SecondLevelCacheFunctionalTestCase
|
||||
self::assertEquals($this->countries[0]->getId(), $result2[0]->getId());
|
||||
self::assertEquals($this->countries[0]->getName(), $result2[0]->getName());
|
||||
|
||||
$result3 = $repository->matching(new Criteria(
|
||||
$result3 = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('name', $this->countries[1]->getName())
|
||||
));
|
||||
|
||||
@@ -108,7 +108,7 @@ class SecondLevelCacheCriteriaTest extends SecondLevelCacheFunctionalTestCase
|
||||
self::assertEquals($this->countries[1]->getId(), $result3[0]->getId());
|
||||
self::assertEquals($this->countries[1]->getName(), $result3[0]->getName());
|
||||
|
||||
$result4 = $repository->matching(new Criteria(
|
||||
$result4 = $repository->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('name', $this->countries[1]->getName())
|
||||
));
|
||||
|
||||
@@ -133,7 +133,7 @@ class SecondLevelCacheCriteriaTest extends SecondLevelCacheFunctionalTestCase
|
||||
$itemName = $this->states[0]->getCities()->get(0)->getName();
|
||||
$this->getQueryLog()->reset()->enable();
|
||||
$collection = $entity->getCities();
|
||||
$matching = $collection->matching(new Criteria(
|
||||
$matching = $collection->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('name', $itemName)
|
||||
));
|
||||
|
||||
@@ -146,7 +146,7 @@ class SecondLevelCacheCriteriaTest extends SecondLevelCacheFunctionalTestCase
|
||||
$entity = $this->_em->find(State::class, $this->states[0]->getId());
|
||||
$this->getQueryLog()->reset()->enable();
|
||||
$collection = $entity->getCities();
|
||||
$matching = $collection->matching(new Criteria(
|
||||
$matching = $collection->matching(Criteria::create(true)->where(
|
||||
Criteria::expr()->eq('name', $itemName)
|
||||
));
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ use Doctrine\Tests\Models\Cache\Country;
|
||||
use Doctrine\Tests\Models\Cache\State;
|
||||
use ReflectionMethod;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/** @group DDC-2183 */
|
||||
class SecondLevelCacheQueryCacheTest extends SecondLevelCacheFunctionalTestCase
|
||||
{
|
||||
@@ -804,7 +806,10 @@ class SecondLevelCacheQueryCacheTest extends SecondLevelCacheFunctionalTestCase
|
||||
|
||||
$getHash = static function (AbstractQuery $query) {
|
||||
$method = new ReflectionMethod($query, 'getHash');
|
||||
$method->setAccessible(true);
|
||||
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
$method->setAccessible(true);
|
||||
}
|
||||
|
||||
return $method->invoke($query);
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user