Compare commits

...

33 Commits

Author SHA1 Message Date
Grégoire Paris
7d84a49980 Setup automated release workflow (#8301) 2020-10-10 19:11:26 +02:00
Claudio Zizza
bb64fc953d Move website config to default branch (#8287)
Adds the website config to be compatible with the doctrine/doctrine-website#356 changes
2020-10-02 20:31:00 +02:00
orklah
e0eb82a3b1 psalm fixes (#8286) 2020-09-30 22:00:38 +02:00
orklah
79cdcde9ec rename parameters to match parents (#8284) 2020-09-26 20:24:11 +02:00
orklah
f4524a8bb0 Fix psalm errors and upgrade strictness (#8209)
* Fixes and improvements

* fix param type
2020-09-25 20:44:07 +02:00
Grégoire Paris
d810ea4111 Use inline literals over escaping (#8279)
Escaping underscores does not work as expected.
See https://www.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/dql-custom-walkers.html#modify-the-output-walker-to-generate-vendor-specific-sql
2020-09-22 20:10:05 +02:00
Michael Voříšek
107ba93d79 Convert CRLF to LF in test file (#8276)
* Convert CRLF to LF in test file
* fix cs
2020-09-21 22:51:49 +02:00
Guillaume Simon
706670215d Fix OrderByItem parser to proceed with SimpleArithmetic expression before function (#8277)
There is parser bug for OrderByItem(), where a function is detected
before a SimpleArithmeticExpression while it should be the reverse:
simple arithmetic expressions can start with a function too, and thus
they should be matched first if present.

This fix enables the use of expressions in sorting and with window
functions.
2020-09-20 18:56:57 +02:00
Yohann Durand
ab2b4987b3 Improve formatting (#8028) 2020-09-08 20:56:51 +02:00
Thomas Landauer
717ef9106c Update events.rst (#8257)
* Update events.rst

Improved code formatting

* Update docs/en/reference/events.rst

I was wondering myself what the `#` was about ;-)

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>

* Update events.rst

See https://github.com/doctrine/orm/pull/8257#discussion_r482305774

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2020-09-03 22:44:28 +02:00
Christoph Ziegenberg
ccae8f7176 Fix for bug #8229 (id column from parent class renamed in child class) (#8234)
This fixes problems with id columns defined in the parent class but renamed in the child class using an attribute override. Before this change always the child column name was used (which was not present in the parent class), now the correct column names are used for the parent table when creating inserts, joins and deletions for it.

Co-authored-by: Crossjoin <crossjoin@users.noreply.github.com>
2020-08-29 13:25:18 +02:00
Grégoire Paris
da18985aca Stop using the DBAL extension of PHPBench (#8252)
It has been removed, and the default XML storage driver is supposed to
be fine for our purposes.
2020-08-29 12:28:40 +02:00
Simon Podlipsky
1e2ed07731 Use consistent formatting in command line (#8238) 2020-08-12 08:38:00 +02:00
Grégoire Paris
424241f29c Use more accurate terminology (#8236)
I think this was a mistake when writing this documentation, and that the
original author meant to use attribute here, columns do not have
columns, they have attributes.
2020-08-09 22:48:52 +02:00
Grégoire Paris
8230afcde9 Fetch deeper
This is needed to preserve parent information and be able to find the
merge base with the head branch. The assumption here is that the common
ancestor can be found among the 10 parent commits.
2020-08-07 22:11:21 +02:00
Kirill Matasov
7cffba8743 Fix annotation in Expr 2020-08-07 22:11:21 +02:00
Benjamin Cremer
7e5fe79349 Change preferred cache driver for metadata and query caches (#8223)
See: https://twitter.com/lcobucci/status/1289087725694484481
2020-08-03 21:40:52 +02:00
njutn95
efd25484f4 Update aggregate-fields.rst (#8215)
Minor typo fix
2020-07-20 21:19:16 +02:00
Andreas Möller
271f3480c8 Fix: Typo (#8213) 2020-07-15 22:46:25 +02:00
orklah
aab589b596 add/fix more types (checked by psalm) (#8199)
* add/fix more psalm types

* remove inexistant SimpleEntityExpression

* Declare template implements for TreeWalkerChainIterator
2020-07-10 22:08:13 +02:00
orklah
190218b267 Change list() syntax to array destructuring (short list syntax) (#8204) 2020-07-07 22:02:34 +02:00
Benjamin Eberlei
181114f2c7 [GH-8106] Move test into existing QueryTest testcase to reduce surface. 2020-07-05 21:51:35 +02:00
tom93
3689b76a86 Fix QueryBuilder::getParameter() on parameter names with colons (#8107)
* Fix type errors

(partially cherry picked from commit 17e7c2a42e)

* Fix QueryBuilder::getParameter() on parameter names with colons

Fixes #8106.

Co-authored-by: Michael Moravec <mail@majkl578.cz>
2020-07-05 21:46:48 +02:00
Igor Pellegrini
75fe18ea5f Add alert to "avoid persisting detached entities" (#8109)
The alert is hidden into the code of ``EntityManager``,
while it's useful to be mentioned in the documentation.
2020-07-05 20:24:08 +02:00
Grégoire Paris
6c73a6b720 Infer return type information with Psalter (#8150)
These changes are a subset of changes done with vendor/bin/psalm --alter
--issues=LessSpecificReturnType
--allow-backwards-incompatible-changes=false
2020-07-05 20:15:39 +02:00
Benjamin Eberlei
775d91c2a3 [GH-8122] Move test from AbstractMappingDriverTest to ClassMetadataFactoryTest case 2020-07-05 20:11:01 +02:00
Gildas Quéméner
64c3f68734 Prohibits class typo in the discriminator map (#8122)
* Prevents incorrect table aliases to be generated

When a defined subclass has a case typo, the query builder will be lost
and will generate exotic table alias. This commit fixes the issue at the
root by prohibiting case typo in discriminator map.

See https://github.com/doctrine/orm/pull/8112 for the consequence of
such typo.

* Controls growing rate of the abstract test class

* Fixes incorrect test case

The Cube class must be autoloaded with the correct case, otherwise
composer autoloader will complain.

* Removes non architecture compliant code

See https://github.com/doctrine/orm/pull/8122/files#r423952247

* Ensures discriminator map is case sensitive
2020-07-05 19:48:38 +02:00
Mohamed Ettaki Talbi
2a2a0b2980 Remove unwanted period (#8198) 2020-07-02 08:36:18 +02:00
vladyslavstartsev
a438e90046 add dev files to .gitattribute (#8190)
those files probably are not used by end user of the lib
2020-06-19 13:48:45 +02:00
Nicolas Grekas
6a670d7d6d Allow using on PHP 7.1 with Composer 2 (#8184) 2020-06-18 23:05:13 +02:00
Grégoire Paris
765521d257 Use CodeCov instead of Scrutinizer (#8187)
* Document current branch status in the README

* Use CodeCov instead of Scrutinizer
2020-06-17 22:47:25 +02:00
Grégoire Paris
5ced62bf83 Run benchmark on PHP 7.4 (#8186)
phpbench recently dropped compatibilty with PHP 7.1
When this job was introduced, 7.1 was the latest version of PHP we
supported, so it makes sense to bump to 7.4 now.
See https://github.com/phpbench/phpbench/releases/tag/0.17.0
See e07c90df44
2020-06-17 22:06:42 +02:00
Alexander Berl
93867f8d77 TASK: Replace "Blacklist" example with "Banlist" (#8174) 2020-06-08 23:06:53 +02:00
119 changed files with 1673 additions and 669 deletions

49
.doctrine-project.json Normal file
View File

@@ -0,0 +1,49 @@
{
"active": true,
"name": "Object Relational Mapper",
"shortName": "ORM",
"slug": "orm",
"docsSlug": "doctrine-orm",
"versions": [
{
"name": "3.0",
"branchName": "master",
"slug": "latest",
"upcoming": true
},
{
"name": "2.8",
"branchName": "2.8.x",
"slug": "2.8",
"upcoming": true
},
{
"name": "2.7",
"branchName": "2.7",
"slug": "2.7",
"current": true,
"aliases": [
"current",
"stable"
]
},
{
"name": "2.6",
"branchName": "2.6",
"slug": "2.6",
"maintained": false
},
{
"name": "2.5",
"branchName": "2.5",
"slug": "2.5",
"maintained": false
},
{
"name": "2.4",
"branchName": "2.4",
"slug": "2.4",
"maintained": false
}
]
}

4
.gitattributes vendored
View File

@@ -1,5 +1,6 @@
/tests export-ignore
/tools export-ignore
/.github export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.gitmodules export-ignore
@@ -11,3 +12,6 @@ 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
psalm.xml export-ignore

View File

@@ -81,6 +81,8 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 10
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
@@ -106,4 +108,4 @@ jobs:
run: "git remote set-branches --add origin $GITHUB_BASE_REF && git fetch origin $GITHUB_BASE_REF"
- name: "Run git-phpcs"
run: "php git-phpcs.phar origin/$GITHUB_BASE_REF...$GITHUB_SHA --report=checkstyle|cs2pr"
run: "php git-phpcs.phar origin/$GITHUB_BASE_REF...$GITHUB_SHA --report=checkstyle | cs2pr"

View File

@@ -0,0 +1,55 @@
name: "Automatic Releases"
on:
milestone:
types:
- "closed"
jobs:
release:
name: "Git tag, release & create merge-up PR"
runs-on: "ubuntu-20.04"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
- name: "Release"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:release"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create Merge-Up Pull Request"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:create-merge-up-pull-request"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create and/or Switch to new Release Branch"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:switch-default-branch-to-next-minor"
env:
"GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create new milestones"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:create-milestones"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}

View File

@@ -1,34 +0,0 @@
build:
nodes:
analysis:
environment:
php:
version: 7.1
cache:
disabled: false
directories:
- ~/.composer/cache
project_setup:
override: true
tests:
override:
- php-scrutinizer-run
before_commands:
- "composer install --no-dev --prefer-source"
tools:
external_code_coverage:
timeout: 3600
filter:
excluded_paths:
- docs
- tools
build_failure_conditions:
- 'elements.rating(<= C).new.exists' # No new classes/methods with a rating of C or worse allowed
- 'issues.severity(>= MAJOR).new.exists' # New issues of major or higher severity
- 'project.metric_change("scrutinizer.test_coverage", < 0)' # Code Coverage decreased from previous inspection
- 'patches.label("Unused Use Statements").new.exists' # No new unused imports patches allowed

View File

@@ -80,12 +80,12 @@ jobs:
- if [[ ! $(php -m | grep -si xdebug) ]]; then echo "xdebug required for coverage"; exit 1; fi
script:
- ENABLE_SECOND_LEVEL_CACHE=0 ./vendor/bin/phpunit -v -c tests/travis/$DB.travis.xml --coverage-clover ./build/logs/clover.xml
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml
after_success:
- bash <(curl -s https://codecov.io/bash) -f ./build/logs/clover.xml
- stage: Code Quality
env: DB=none BENCHMARK
php: 7.4
before_script: wget https://phpbench.github.io/phpbench/phpbench.phar https://phpbench.github.io/phpbench/phpbench.phar.pubkey
script: php phpbench.phar run -l dots --report=default

View File

@@ -1,7 +1,7 @@
| [Master][Master] | [2.5][2.5] |
| [Master][Master] | [2.7][2.7] |
|:----------------:|:----------:|
| [![Build status][Master image]][Master] | [![Build status][2.5 image]][2.5] |
| [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.5 coverage image]][2.5 coverage] |
| [![Build status][Master image]][Master] | [![Build status][2.7 image]][2.7] |
| [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.7 coverage image]][2.7 coverage] |
Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
@@ -18,9 +18,9 @@ without requiring unnecessary code duplication.
[Master image]: https://img.shields.io/travis/doctrine/orm/master.svg?style=flat-square
[Master]: https://travis-ci.org/doctrine/orm
[Master coverage image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/orm/master.svg?style=flat-square
[Master coverage]: https://scrutinizer-ci.com/g/doctrine/orm/?branch=master
[2.5 image]: https://img.shields.io/travis/doctrine/orm/2.5.svg?style=flat-square
[2.5]: https://github.com/doctrine/orm/tree/2.5
[2.5 coverage image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/orm/2.5.svg?style=flat-square
[2.5 coverage]: https://scrutinizer-ci.com/g/doctrine/orm/?branch=2.5
[Master coverage image]: https://codecov.io/gh/doctrine/orm/branch/master/graph/badge.svg
[Master coverage]: https://codecov.io/gh/doctrine/orm/branch/master
[2.7 image]: https://img.shields.io/travis/doctrine/orm/2.7.svg?style=flat-square
[2.7]: https://github.com/doctrine/orm/tree/2.7
[2.7 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.7/graph/badge.svg
[2.7 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.7

View File

@@ -21,6 +21,7 @@
"require": {
"php": "^7.1",
"ext-pdo": "*",
"composer/package-versions-deprecated": "^1.8",
"doctrine/annotations": "^1.8",
"doctrine/cache": "^1.9.1",
"doctrine/collections": "^1.5",
@@ -31,7 +32,6 @@
"doctrine/instantiator": "^1.3",
"doctrine/lexer": "^1.0",
"doctrine/persistence": "^1.3.3 || ^2.0",
"ocramius/package-versions": "^1.2",
"symfony/console": "^3.0|^4.0|^5.0"
},
"require-dev": {

122
composer.lock generated
View File

@@ -1,11 +1,76 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2b7c09043b3b7d625abd8ee130abb16b",
"content-hash": "8f74f1ed98af4508fc136e982596658b",
"packages": [
{
"name": "composer/package-versions-deprecated",
"version": "1.8.0",
"source": {
"type": "git",
"url": "https://github.com/composer/package-versions-deprecated.git",
"reference": "98df7f1b293c0550bd5b1ce6b60b59bdda23aa47"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/98df7f1b293c0550bd5b1ce6b60b59bdda23aa47",
"reference": "98df7f1b293c0550bd5b1ce6b60b59bdda23aa47",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.1.0 || ^2.0",
"php": "^7"
},
"replace": {
"ocramius/package-versions": "1.2 - 1.8.99"
},
"require-dev": {
"composer/composer": "^1.9.3 || ^2.0@dev",
"ext-zip": "^1.13",
"phpunit/phpunit": "^6.5 || ^7"
},
"type": "composer-plugin",
"extra": {
"class": "PackageVersions\\Installer",
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"PackageVersions\\": "src/PackageVersions"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be"
}
],
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2020-04-23T11:49:37+00:00"
},
{
"name": "doctrine/annotations",
"version": "1.10.3",
@@ -801,56 +866,6 @@
],
"time": "2020-03-27T11:06:43+00:00"
},
{
"name": "ocramius/package-versions",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/Ocramius/PackageVersions.git",
"reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/44af6f3a2e2e04f2af46bcb302ad9600cba41c7d",
"reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0.0",
"php": "^7.1.0"
},
"require-dev": {
"composer/composer": "^1.6.3",
"doctrine/coding-standard": "^5.0.1",
"ext-zip": "*",
"infection/infection": "^0.7.1",
"phpunit/phpunit": "^7.5.17"
},
"type": "composer-plugin",
"extra": {
"class": "PackageVersions\\Installer",
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"PackageVersions\\": "src/PackageVersions"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
"time": "2019-11-15T16:17:10+00:00"
},
{
"name": "psr/container",
"version": "1.0.0",
@@ -3614,5 +3629,6 @@
"platform-dev": [],
"platform-overrides": {
"php": "7.1.3"
}
},
"plugin-api-version": "1.1.0"
}

View File

@@ -22,7 +22,7 @@ into the account can either be of positive or negative money
values. Each account has a credit limit and the account is never
allowed to have a balance below that value.
For simplicity we live in a world were money is composed of
For simplicity we live in a world where money is composed of
integers only. Also we omit the receiver/sender name, stated reason
for transfer and the execution date. These all would have to be
added on the ``Entry`` object.

View File

@@ -167,7 +167,7 @@ can be set via ``Query::setHint($name, $value)`` as shown in the
previous example with the ``HINT_CUSTOM_TREE_WALKERS`` query hint.
We will implement a custom Output Walker that allows to specify the
SQL\_NO\_CACHE query hint.
``SQL_NO_CACHE`` query hint.
.. code-block:: php
@@ -180,7 +180,7 @@ SQL\_NO\_CACHE query hint.
Our ``MysqlWalker`` will extend the default ``SqlWalker``. We will
modify the generation of the SELECT clause, adding the
SQL\_NO\_CACHE on those queries that need it:
``SQL_NO_CACHE`` on those queries that need it:
.. code-block:: php

View File

@@ -18,9 +18,9 @@ This chapter is split into three different sections.
One tip for working with relations is to read the relation from left to right, where the left word refers to the current Entity. For example:
- OneToMany - One instance of the current Entity has Many instances (references) to the refered Entity.
- ManyToOne - Many instances of the current Entity refer to One instance of the refered Entity.
- OneToOne - One instance of the current Entity refers to One instance of the refered Entity.
- OneToMany - One instance of the current Entity has Many instances (references) to the referred Entity.
- ManyToOne - Many instances of the current Entity refer to One instance of the referred Entity.
- OneToOne - One instance of the current Entity refers to One instance of the referred Entity.
See below for all the possible relations.

View File

@@ -491,7 +491,7 @@ Joins between entities without associations were not possible until version
.. code-block:: php
<?php
$query = $em->createQuery('SELECT u FROM User u JOIN Blacklist b WITH u.email = b.email');
$query = $em->createQuery('SELECT u FROM User u JOIN Banlist b WITH u.email = b.email');
.. note::
The differences between WHERE, WITH and HAVING clauses may be

View File

@@ -145,49 +145,53 @@ An example for a correct notation can be found in the example
Lifecycle Events
----------------
The EntityManager and UnitOfWork trigger a bunch of events during
the life-time of their registered entities.
The ``EntityManager`` and ``UnitOfWork`` classes trigger a bunch of
events during the life-time of their registered entities.
- preRemove - The preRemove event occurs for a given entity before
the respective EntityManager remove operation for that entity is
executed. It is not called for a DQL DELETE statement.
- postRemove - The postRemove event occurs for an entity after the
- ``preRemove`` - The ``preRemove`` event occurs for a given entity
before the respective ``EntityManager`` remove operation for that
entity is executed. It is not called for a DQL ``DELETE`` statement.
- ``postRemove`` - The ``postRemove`` event occurs for an entity after the
entity has been deleted. It will be invoked after the database
delete operations. It is not called for a DQL DELETE statement.
- prePersist - The prePersist event occurs for a given entity
before the respective EntityManager persist operation for that
delete operations. It is not called for a DQL ``DELETE`` statement.
- ``prePersist`` - The ``prePersist`` event occurs for a given entity
before the respective ``EntityManager`` persist operation for that
entity is executed. It should be noted that this event is only triggered on
*initial* persist of an entity (i.e. it does not trigger on future updates).
- postPersist - The postPersist event occurs for an entity after
- ``postPersist`` - The ``postPersist`` event occurs for an entity after
the entity has been made persistent. It will be invoked after the
database insert operations. Generated primary key values are
available in the postPersist event.
- preUpdate - The preUpdate event occurs before the database
update operations to entity data. It is not called for a DQL UPDATE statement
nor when the computed changeset is empty.
- postUpdate - The postUpdate event occurs after the database
update operations to entity data. It is not called for a DQL UPDATE statement.
- postLoad - The postLoad event occurs for an entity after the
entity has been loaded into the current EntityManager from the
- ``preUpdate`` - The ``preUpdate`` event occurs before the database
update operations to entity data. It is not called for a DQL
``UPDATE`` statement nor when the computed changeset is empty.
- ``postUpdate`` - The ``postUpdate`` event occurs after the database
update operations to entity data. It is not called for a DQL
``UPDATE`` statement.
- ``postLoad`` - The postLoad event occurs for an entity after the
entity has been loaded into the current ``EntityManager`` from the
database or after the refresh operation has been applied to it.
- loadClassMetadata - The loadClassMetadata event occurs after the
- ``loadClassMetadata`` - The ``loadClassMetadata`` event occurs after the
mapping metadata for a class has been loaded from a mapping source
(annotations/xml/yaml). This event is not a lifecycle callback.
- onClassMetadataNotFound - Loading class metadata for a particular
- ``onClassMetadataNotFound`` - Loading class metadata for a particular
requested class name failed. Manipulating the given event args instance
allows providing fallback metadata even when no actual metadata exists
or could be found. This event is not a lifecycle callback.
- preFlush - The preFlush event occurs at the very beginning of a flush
operation.
- onFlush - The onFlush event occurs after the change-sets of all
- ``preFlush`` - The ``preFlush`` event occurs at the very beginning of
a flush operation.
- ``onFlush`` - The ``onFlush`` event occurs after the change-sets of all
managed entities are computed. This event is not a lifecycle
callback.
- postFlush - The postFlush event occurs at the end of a flush operation. This
- ``postFlush`` - The ``postFlush`` event occurs at the end of a flush operation. This
event is not a lifecycle callback.
- onClear - The onClear event occurs when the EntityManager#clear() operation is
invoked, after all references to entities have been removed from the unit of
work. This event is not a lifecycle callback.
- ``onClear`` - The ``onClear`` event occurs when the
``EntityManager#clear()`` operation is invoked, after all references
to entities have been removed from the unit of work. This event is not
a lifecycle callback.
.. warning::
@@ -199,7 +203,7 @@ the life-time of their registered entities.
.. warning::
Note that the postRemove event or any events triggered after an entity removal
Note that the ``postRemove`` event or any events triggered after an entity removal
can receive an uninitializable proxy in case you have configured an entity to
cascade remove relations. In this case, you should load yourself the proxy in
the associated pre event.
@@ -222,13 +226,13 @@ listeners:
- Lifecycle Event Listeners and Subscribers are classes with specific callback
methods that receives some kind of ``EventArgs`` instance.
The EventArgs instance received by the listener gives access to the entity,
EntityManager and other relevant data.
The ``EventArgs`` instance received by the listener gives access to the entity,
``EntityManager`` instance and other relevant data.
.. note::
All Lifecycle events that happen during the ``flush()`` of
an EntityManager have very specific constraints on the allowed
an ``EntityManager`` have very specific constraints on the allowed
operations that can be executed. Please read the
:ref:`reference-events-implementing-listeners` section very carefully
to understand which operations are allowed in which lifecycle event.
@@ -410,9 +414,9 @@ sit at a level above the entities and allow you to implement re-usable
behaviors across different entity classes.
Note that they require much more detailed knowledge about the inner
workings of the EntityManager and UnitOfWork. Please read the
:ref:`reference-events-implementing-listeners` section carefully if you
are trying to write your own listener.
workings of the ``EntityManager`` and ``UnitOfWork`` classes. Please
read the :ref:`reference-events-implementing-listeners` section
carefully if you are trying to write your own listener.
For event subscribers, there are no surprises. They declare the
lifecycle events in their ``getSubscribedEvents`` method and provide
@@ -501,16 +505,16 @@ Implementing Event Listeners
----------------------------
This section explains what is and what is not allowed during
specific lifecycle events of the UnitOfWork. Although you get
passed the EntityManager in all of these events, you have to follow
these restrictions very carefully since operations in the wrong
event may produce lots of different errors, such as inconsistent
specific lifecycle events of the ``UnitOfWork`` class. Although you get
passed the ``EntityManager`` instance in all of these events, you have
to follow these restrictions very carefully since operations in the
wrong event may produce lots of different errors, such as inconsistent
data and lost updates/persists/removes.
For the described events that are also lifecycle callback events
the restrictions apply as well, with the additional restriction
that (prior to version 2.4) you do not have access to the
EntityManager or UnitOfWork APIs inside these events.
``EntityManager`` or ``UnitOfWork`` APIs inside these events.
prePersist
~~~~~~~~~~
@@ -586,8 +590,8 @@ entities and their associations have been computed. This means, the
- Collections scheduled for update
- Collections scheduled for removal
To make use of the onFlush event you have to be familiar with the
internal UnitOfWork API, which grants you access to the previously
To make use of the ``onFlush`` event you have to be familiar with the
internal ``UnitOfWork`` API, which grants you access to the previously
mentioned sets. See this example:
.. code-block:: php
@@ -735,7 +739,7 @@ Restrictions for this event:
the event to modify primitive field values, e.g. use
``$eventArgs->setNewValue($field, $value);`` as in the Alice to Bob example above.
- Any calls to ``EntityManager#persist()`` or
``EntityManager#remove()``, even in combination with the UnitOfWork
``EntityManager#remove()``, even in combination with the ``UnitOfWork``
API are strongly discouraged and don't work as expected outside the
flush operation.
@@ -991,4 +995,3 @@ process and manipulate the instance.
}
}

View File

@@ -20,12 +20,17 @@ Metadata and Query caches
As already mentioned earlier in the chapter about configuring
Doctrine, it is strongly discouraged to use Doctrine without a
Metadata and Query cache (preferably with APC or Memcache as the
cache driver). Operating Doctrine without these caches means
Metadata and Query cache.
Operating Doctrine without these caches means
Doctrine will need to load your mapping information on every single
request and has to parse each DQL query on every single request.
This is a waste of resources.
The preferred cache driver for metadata and query caches is ``PhpFileCache``.
This driver serializes cache items and writes them to a file.
This allows for opcode caching to be used and provides high performance in most scenarios.
See :ref:`integrating-with-the-orm`
Alternative Query Result Formats

View File

@@ -584,7 +584,7 @@ Things to note:
- The "attribute override" specifies the overrides base on the property name.
- The column type *CANNOT* be changed. If the column type is not equal you get a ``MappingException``
- The override can redefine all the columns except the type.
- The override can redefine all the attributes except the type.
Query the Type
--------------

View File

@@ -250,6 +250,12 @@ as follows:
- If X is a detached entity, an exception will be thrown on
flush.
.. caution::
Do not pass detached entities to the persist operation. The persist operation always
considers entities that are not yet known to the ``EntityManager`` as new entities
(refer to the ``STATE_NEW`` constant inside the ``UnitOfWork``).
Removing entities
-----------------

View File

@@ -3,7 +3,7 @@ Extra Lazy Associations
.. versionadded:: 2.1
In many cases associations between entities can get pretty large. Even in a simple scenario like a blog.
In many cases associations between entities can get pretty large. Even in a simple scenario like a blog
where posts can be commented, you always have to assume that a post draws hundreds of comments.
In Doctrine 2.0 if you accessed an association it would always get loaded completely into memory. This
can lead to pretty serious performance problems, if your associations contain several hundreds or thousands

View File

@@ -72,6 +72,7 @@ abstract class AbstractQuery
* The parameter map of this query.
*
* @var ArrayCollection|Parameter[]
* @psalm-var ArrayCollection<int, Parameter>
*/
protected $parameters;
@@ -240,7 +241,7 @@ abstract class AbstractQuery
*
* @param integer $lifetime
*
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return static This query instance.
*/
public function setLifetime($lifetime)
{
@@ -260,7 +261,7 @@ abstract class AbstractQuery
/**
* @param integer $cacheMode
*
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return static This query instance.
*/
public function setCacheMode($cacheMode)
{
@@ -321,11 +322,13 @@ abstract class AbstractQuery
*/
public function getParameter($key)
{
$key = Query\Parameter::normalizeName($key);
$filteredParameters = $this->parameters->filter(
function (Query\Parameter $parameter) use ($key) : bool {
$parameterName = $parameter->getName();
return $key === $parameterName || (string) $key === (string) $parameterName;
return $key === $parameterName;
}
);
@@ -338,11 +341,14 @@ abstract class AbstractQuery
* @param ArrayCollection|mixed[] $parameters
*
* @return static This query instance.
*
* @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters
*/
public function setParameters($parameters)
{
// BC compatibility with 2.3-
if (is_array($parameters)) {
/** @psalm-var ArrayCollection<int, Parameter> $parameterCollection */
$parameterCollection = new ArrayCollection();
foreach ($parameters as $key => $value) {
@@ -388,9 +394,11 @@ abstract class AbstractQuery
*
* @param mixed $value
*
* @return array|string
* @return mixed[]|string|int|float|bool
*
* @throws \Doctrine\ORM\ORMInvalidArgumentException
*
* @psalm-return array|scalar
*/
public function processParameterValue($value)
{
@@ -468,7 +476,7 @@ abstract class AbstractQuery
*/
private function translateNamespaces(Query\ResultSetMapping $rsm)
{
$translate = function ($alias) {
$translate = function ($alias) : string {
return $this->_em->getClassMetadata($alias)->getName();
};
@@ -629,7 +637,7 @@ abstract class AbstractQuery
/**
* Defines how long the result cache will be active before expire.
*
* @param integer $lifetime How long the cache entry is valid.
* @param int|null $lifetime How long the cache entry is valid.
*
* @return static This query instance.
*/
@@ -964,10 +972,11 @@ abstract class AbstractQuery
$this->setParameters($parameters);
}
$setCacheEntry = function() {};
$setCacheEntry = static function () : void {
};
if ($this->_hydrationCacheProfile !== null) {
list($cacheKey, $realCacheKey) = $this->getHydrationCacheId();
[$cacheKey, $realCacheKey] = $this->getHydrationCacheId();
$queryCacheProfile = $this->getHydrationCacheProfile();
$cache = $queryCacheProfile->getResultCacheDriver();
@@ -981,7 +990,7 @@ abstract class AbstractQuery
$result = [];
}
$setCacheEntry = function($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) {
$setCacheEntry = static function ($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) : void {
$result[$realCacheKey] = $data;
$cache->save($cacheKey, $result, $queryCacheProfile->getLifetime());
@@ -1068,7 +1077,7 @@ abstract class AbstractQuery
* Will return the configured id if it exists otherwise a hash will be
* automatically generated for you.
*
* @return array ($key, $hash)
* @return array<string, string> ($key, $hash)
*/
protected function getHydrationCacheId()
{

View File

@@ -60,9 +60,6 @@ class DefaultCache implements Cache
*/
private $defaultQueryCache;
/**
* {@inheritdoc}
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;

View File

@@ -348,7 +348,9 @@ class DefaultQueryCache implements QueryCache
* @param array $assoc
* @param mixed $assocValue
*
* @return array|null
* @return mixed[]|null
*
* @psalm-return array{targetEntity: string, type: mixed, list?: array[], identifier?: array}|null
*/
private function storeAssociationCache(QueryCacheKey $key, array $assoc, $assocValue)
{

View File

@@ -33,17 +33,17 @@ use Doctrine\ORM\Cache\QueryCacheKey;
class StatisticsCacheLogger implements CacheLogger
{
/**
* @var array
* @var int[]
*/
private $cacheMissCountMap = [];
/**
* @var array
* @var int[]
*/
private $cacheHitCountMap = [];
/**
* @var array
* @var int[]
*/
private $cachePutCountMap = [];
@@ -142,7 +142,7 @@ class StatisticsCacheLogger implements CacheLogger
*
* @param string $regionName The name of the cache region.
*
* @return integer
* @return int
*/
public function getRegionHitCount($regionName)
{
@@ -154,7 +154,7 @@ class StatisticsCacheLogger implements CacheLogger
*
* @param string $regionName The name of the cache region.
*
* @return integer
* @return int
*/
public function getRegionMissCount($regionName)
{
@@ -166,7 +166,7 @@ class StatisticsCacheLogger implements CacheLogger
*
* @param string $regionName The name of the cache region.
*
* @return integer
* @return int
*/
public function getRegionPutCount($regionName)
{
@@ -222,7 +222,7 @@ class StatisticsCacheLogger implements CacheLogger
/**
* Get the total number of put in cache.
*
* @return integer
* @return int
*/
public function getPutCount()
{
@@ -232,7 +232,7 @@ class StatisticsCacheLogger implements CacheLogger
/**
* Get the total number of entries successfully retrieved from cache.
*
* @return integer
* @return int
*/
public function getHitCount()
{
@@ -242,7 +242,7 @@ class StatisticsCacheLogger implements CacheLogger
/**
* Get the total number of cached entries *not* found in cache.
*
* @return integer
* @return int
*/
public function getMissCount()
{

View File

@@ -144,7 +144,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
* @param \Doctrine\ORM\PersistentCollection $collection
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key
*
* @return \Doctrine\ORM\PersistentCollection|null
* @return object[]|null
*/
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key)
{

View File

@@ -283,17 +283,17 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* Generates a string of currently query
*
* @param array $query
* @param string $criteria
* @param array $orderBy
* @param integer $limit
* @param integer $offset
* @param string $query
* @param string[]|Criteria $criteria
* @param string[] $orderBy
* @param int $limit
* @param int $offset
*
* @return string
*/
protected function getHash($query, $criteria, array $orderBy = null, $limit = null, $offset = null)
{
list($params) = ($criteria instanceof Criteria)
[$params] = $criteria instanceof Criteria
? $this->persister->expandCriteriaParameters($criteria)
: $this->persister->expandParameters($criteria);
@@ -544,19 +544,18 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritdoc}
*/
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
{
$persister = $this->uow->getCollectionPersister($assoc);
$hasCache = ($persister instanceof CachedPersister);
$key = null;
if ( ! $hasCache) {
return $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $coll);
return $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection);
}
$ownerId = $this->uow->getEntityIdentifier($coll->getOwner());
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
$key = $this->buildCollectionCacheKey($assoc, $ownerId);
$list = $persister->loadCollectionCache($coll, $key);
$list = $persister->loadCollectionCache($collection, $key);
if ($list !== null) {
if ($this->cacheLogger) {
@@ -566,7 +565,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $list;
}
$list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $coll);
$list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection);
$persister->storeCollectionCache($key, $list);
@@ -580,18 +579,18 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritdoc}
*/
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
{
$persister = $this->uow->getCollectionPersister($assoc);
$hasCache = ($persister instanceof CachedPersister);
if ( ! $hasCache) {
return $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $coll);
return $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection);
}
$ownerId = $this->uow->getEntityIdentifier($coll->getOwner());
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
$key = $this->buildCollectionCacheKey($assoc, $ownerId);
$list = $persister->loadCollectionCache($coll, $key);
$list = $persister->loadCollectionCache($collection, $key);
if ($list !== null) {
if ($this->cacheLogger) {
@@ -601,7 +600,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $list;
}
$list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $coll);
$list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection);
$persister->storeCollectionCache($key, $list);

View File

@@ -100,6 +100,12 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
$this->queuedCache['update'][] = $entity;
}
/**
* @param object $entity
* @param bool $isChanged
*
* @return bool
*/
private function updateCache($entity, $isChanged)
{
$class = $this->metadataFactory->getMetadataFor(get_class($entity));

View File

@@ -249,6 +249,8 @@ class FileLockRegion implements ConcurrentRegion
/**
* {@inheritdoc}
*
* @return bool
*/
public function unlock(CacheKey $key, Lock $lock)
{

View File

@@ -65,7 +65,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function beginTransaction()
{
return $this->wrapped->beginTransaction();
$this->wrapped->beginTransaction();
}
/**
@@ -81,7 +81,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function commit()
{
return $this->wrapped->commit();
$this->wrapped->commit();
}
/**
@@ -89,7 +89,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function rollback()
{
return $this->wrapped->rollback();
$this->wrapped->rollback();
}
/**
@@ -153,7 +153,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function close()
{
return $this->wrapped->close();
$this->wrapped->close();
}
/**
@@ -169,15 +169,15 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function lock($entity, $lockMode, $lockVersion = null)
{
return $this->wrapped->lock($entity, $lockMode, $lockVersion);
$this->wrapped->lock($entity, $lockMode, $lockVersion);
}
/**
* {@inheritdoc}
*/
public function find($entityName, $id, $lockMode = null, $lockVersion = null)
public function find($className, $id, $lockMode = null, $lockVersion = null)
{
return $this->wrapped->find($entityName, $id, $lockMode, $lockVersion);
return $this->wrapped->find($className, $id, $lockMode, $lockVersion);
}
/**
@@ -185,7 +185,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function flush($entity = null)
{
return $this->wrapped->flush($entity);
$this->wrapped->flush($entity);
}
/**

View File

@@ -31,6 +31,7 @@ use Doctrine\Common\Util\ClassUtils;
use Doctrine\Persistence\Mapping\MappingException;
use Doctrine\Persistence\ObjectRepository;
use Throwable;
use function ltrim;
use const E_USER_DEPRECATED;
use function trigger_error;
@@ -327,7 +328,7 @@ use function trigger_error;
*/
public function createNamedNativeQuery($name)
{
list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
[$sql, $rsm] = $this->config->getNamedNativeQuery($name);
return $this->createNativeQuery($sql, $rsm);
}
@@ -373,7 +374,7 @@ use function trigger_error;
/**
* Finds an Entity by its identifier.
*
* @param string $entityName The class name of the entity to find.
* @param string $className The class name of the entity to find.
* @param mixed $id The identity of the entity to find.
* @param integer|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
* or NULL if no specific lock mode should be used
@@ -388,9 +389,9 @@ use function trigger_error;
* @throws TransactionRequiredException
* @throws ORMException
*/
public function find($entityName, $id, $lockMode = null, $lockVersion = null)
public function find($className, $id, $lockMode = null, $lockVersion = null)
{
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
$class = $this->metadataFactory->getMetadataFor(ltrim($className, '\\'));
if ($lockMode !== null) {
$this->checkLockRequirements($lockMode, $class);

View File

@@ -38,7 +38,7 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
private $em;
/**
* @var string
* @var string|null
*/
private $entityClass;

View File

@@ -40,7 +40,7 @@ abstract class AbstractIdGenerator
* By default, this method returns FALSE. Generators that have this requirement
* must override this method and return TRUE.
*
* @return boolean
* @return bool
*/
public function isPostInsertGenerator()
{

View File

@@ -228,14 +228,14 @@ abstract class AbstractHydrator
*
* Template method.
*
* @param array $data The row data.
* @param array $result The result to fill.
* @param mixed[] $row The row data.
* @param mixed[] $result The result to fill.
*
* @return void
*
* @throws HydrationException
*/
protected function hydrateRowData(array $data, array &$result)
protected function hydrateRowData(array $row, array &$result)
{
throw new HydrationException("hydrateRowData() not implemented by this hydrator.");
}
@@ -260,8 +260,19 @@ abstract class AbstractHydrator
* @param array &$id Dql-Alias => ID-Hash.
* @param array &$nonemptyComponents Does this DQL-Alias has at least one non NULL value?
*
* @return array An array with all the fields (name => value) of the data row,
* grouped by their component alias.
* @return array<string, array<string, mixed>> An array with all the fields
* (name => value) of the data
* row, grouped by their
* component alias.
*
* @psalm-return array{
* data: array<array-key, array>,
* newObjects?: array<array-key, array{
* class: mixed,
* args?: array
* }>,
* scalars?: array
* }
*/
protected function gatherRowData(array $data, array &$id, array &$nonemptyComponents)
{

View File

@@ -47,8 +47,8 @@ class ScalarHydrator extends AbstractHydrator
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $data, array &$result)
protected function hydrateRowData(array $row, array &$result)
{
$result[] = $this->gatherScalarRowData($data);
$result[] = $this->gatherScalarRowData($row);
}
}

View File

@@ -22,6 +22,7 @@ namespace Doctrine\ORM\Internal\Hydration;
use PDO;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query;
use function array_keys;
use function in_array;
class SimpleObjectHydrator extends AbstractHydrator
@@ -77,7 +78,7 @@ class SimpleObjectHydrator extends AbstractHydrator
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $sqlResult, array &$result)
protected function hydrateRowData(array $row, array &$result)
{
$entityName = $this->class->name;
$data = [];
@@ -92,27 +93,27 @@ class SimpleObjectHydrator extends AbstractHydrator
$discrColumnName = $metaMappingDiscrColumnName;
}
if ( ! isset($sqlResult[$discrColumnName])) {
if (! isset($row[$discrColumnName])) {
throw HydrationException::missingDiscriminatorColumn($entityName, $discrColumnName, key($this->_rsm->aliasMap));
}
if ($sqlResult[$discrColumnName] === '') {
if ($row[$discrColumnName] === '') {
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
}
$discrMap = $this->class->discriminatorMap;
if ( ! isset($discrMap[$sqlResult[$discrColumnName]])) {
throw HydrationException::invalidDiscriminatorValue($sqlResult[$discrColumnName], array_keys($discrMap));
if (! isset($discrMap[$row[$discrColumnName]])) {
throw HydrationException::invalidDiscriminatorValue($row[$discrColumnName], array_keys($discrMap));
}
$entityName = $discrMap[$sqlResult[$discrColumnName]];
$discrColumnValue = $sqlResult[$discrColumnName];
$entityName = $discrMap[$row[$discrColumnName]];
$discrColumnValue = $row[$discrColumnName];
unset($sqlResult[$discrColumnName]);
unset($row[$discrColumnName]);
}
foreach ($sqlResult as $column => $value) {
foreach ($row as $column => $value) {
// An ObjectHydrator should be used instead of SimpleObjectHydrator
if (isset($this->_rsm->relationMap[$column])) {
throw new \Exception(sprintf('Unable to retrieve association information for column "%s"', $column));

View File

@@ -89,7 +89,7 @@ final class HydrationCompleteHandler
$this->deferredPostLoadInvocations = [];
foreach ($toInvoke as $classAndEntity) {
list($class, $invoke, $entity) = $classAndEntity;
[$class, $invoke, $entity] = $classAndEntity;
$this->listenersInvoker->invoke(
$class,

View File

@@ -58,7 +58,7 @@ class AssociationBuilder
/**
* @param string $fieldName
*
* @return AssociationBuilder
* @return static
*/
public function mappedBy($fieldName)
{
@@ -70,7 +70,7 @@ class AssociationBuilder
/**
* @param string $fieldName
*
* @return AssociationBuilder
* @return static
*/
public function inversedBy($fieldName)
{
@@ -80,7 +80,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeAll()
{
@@ -90,7 +90,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadePersist()
{
@@ -100,7 +100,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeRemove()
{
@@ -110,7 +110,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeMerge()
{
@@ -120,7 +120,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeDetach()
{
@@ -130,7 +130,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeRefresh()
{
@@ -140,7 +140,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function fetchExtraLazy()
{
@@ -150,7 +150,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function fetchEager()
{
@@ -160,7 +160,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function fetchLazy()
{
@@ -179,7 +179,7 @@ class AssociationBuilder
* @param string|null $onDelete
* @param string|null $columnDef
*
* @return AssociationBuilder
* @return static
*/
public function addJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
{
@@ -198,7 +198,7 @@ class AssociationBuilder
/**
* Sets field as primary key.
*
* @return self
* @return static
*/
public function makePrimaryKey()
{
@@ -210,7 +210,7 @@ class AssociationBuilder
/**
* Removes orphan entities when detached from their parent.
*
* @return self
* @return static
*/
public function orphanRemoval()
{

View File

@@ -57,7 +57,7 @@ class ClassMetadataBuilder
/**
* Marks the class as mapped superclass.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setMappedSuperClass()
{
@@ -70,7 +70,7 @@ class ClassMetadataBuilder
/**
* Marks the class as embeddable.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setEmbeddable()
{
@@ -107,7 +107,7 @@ class ClassMetadataBuilder
*
* @param string $repositoryClassName
*
* @return ClassMetadataBuilder
* @return static
*/
public function setCustomRepositoryClass($repositoryClassName)
{
@@ -119,7 +119,7 @@ class ClassMetadataBuilder
/**
* Marks class read only.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setReadOnly()
{
@@ -133,7 +133,7 @@ class ClassMetadataBuilder
*
* @param string $name
*
* @return ClassMetadataBuilder
* @return static
*/
public function setTable($name)
{
@@ -148,7 +148,7 @@ class ClassMetadataBuilder
* @param array $columns
* @param string $name
*
* @return ClassMetadataBuilder
* @return static
*/
public function addIndex(array $columns, $name)
{
@@ -167,7 +167,7 @@ class ClassMetadataBuilder
* @param array $columns
* @param string $name
*
* @return ClassMetadataBuilder
* @return static
*/
public function addUniqueConstraint(array $columns, $name)
{
@@ -186,7 +186,7 @@ class ClassMetadataBuilder
* @param string $name
* @param string $dqlQuery
*
* @return ClassMetadataBuilder
* @return static
*/
public function addNamedQuery($name, $dqlQuery)
{
@@ -203,7 +203,7 @@ class ClassMetadataBuilder
/**
* Sets class as root of a joined table inheritance hierarchy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setJoinedTableInheritance()
{
@@ -215,7 +215,7 @@ class ClassMetadataBuilder
/**
* Sets class as root of a single table inheritance hierarchy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setSingleTableInheritance()
{
@@ -231,7 +231,7 @@ class ClassMetadataBuilder
* @param string $type
* @param int $length
*
* @return ClassMetadataBuilder
* @return static
*/
public function setDiscriminatorColumn($name, $type = 'string', $length = 255)
{
@@ -252,7 +252,7 @@ class ClassMetadataBuilder
* @param string $name
* @param string $class
*
* @return ClassMetadataBuilder
* @return static
*/
public function addDiscriminatorMapClass($name, $class)
{
@@ -264,7 +264,7 @@ class ClassMetadataBuilder
/**
* Sets deferred explicit change tracking policy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setChangeTrackingPolicyDeferredExplicit()
{
@@ -276,7 +276,7 @@ class ClassMetadataBuilder
/**
* Sets notify change tracking policy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setChangeTrackingPolicyNotify()
{
@@ -291,7 +291,7 @@ class ClassMetadataBuilder
* @param string $methodName
* @param string $event
*
* @return ClassMetadataBuilder
* @return static
*/
public function addLifecycleEvent($methodName, $event)
{
@@ -307,7 +307,7 @@ class ClassMetadataBuilder
* @param string $type
* @param array $mapping
*
* @return ClassMetadataBuilder
* @return static
*/
public function addField($name, $type, array $mapping = [])
{

View File

@@ -74,7 +74,7 @@ class FieldBuilder
*
* @param int $length
*
* @return FieldBuilder
* @return static
*/
public function length($length)
{
@@ -88,7 +88,7 @@ class FieldBuilder
*
* @param bool $flag
*
* @return FieldBuilder
* @return static
*/
public function nullable($flag = true)
{
@@ -102,7 +102,7 @@ class FieldBuilder
*
* @param bool $flag
*
* @return FieldBuilder
* @return static
*/
public function unique($flag = true)
{
@@ -116,7 +116,7 @@ class FieldBuilder
*
* @param string $name
*
* @return FieldBuilder
* @return static
*/
public function columnName($name)
{
@@ -130,7 +130,7 @@ class FieldBuilder
*
* @param int $p
*
* @return FieldBuilder
* @return static
*/
public function precision($p)
{
@@ -144,7 +144,7 @@ class FieldBuilder
*
* @param int $s
*
* @return FieldBuilder
* @return static
*/
public function scale($s)
{
@@ -167,7 +167,7 @@ class FieldBuilder
/**
* Sets field as primary key.
*
* @return FieldBuilder
* @return static
*/
public function makePrimaryKey()
{
@@ -182,7 +182,7 @@ class FieldBuilder
* @param string $name
* @param mixed $value
*
* @return FieldBuilder
* @return static
*/
public function option($name, $value)
{
@@ -194,7 +194,7 @@ class FieldBuilder
/**
* @param string $strategy
*
* @return FieldBuilder
* @return static
*/
public function generatedValue($strategy = 'AUTO')
{
@@ -206,7 +206,7 @@ class FieldBuilder
/**
* Sets field versioned.
*
* @return FieldBuilder
* @return static
*/
public function isVersionField()
{
@@ -222,7 +222,7 @@ class FieldBuilder
* @param int $allocationSize
* @param int $initialValue
*
* @return FieldBuilder
* @return static
*/
public function setSequenceGenerator($sequenceName, $allocationSize = 1, $initialValue = 1)
{
@@ -240,7 +240,7 @@ class FieldBuilder
*
* @param string $def
*
* @return FieldBuilder
* @return static
*/
public function columnDefinition($def)
{

View File

@@ -42,7 +42,7 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
/**
* @param string $name
*
* @return ManyToManyAssociationBuilder
* @return static
*/
public function setJoinTable($name)
{
@@ -61,7 +61,7 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
* @param string|null $onDelete
* @param string|null $columnDef
*
* @return ManyToManyAssociationBuilder
* @return static
*/
public function addInverseJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
{

View File

@@ -32,7 +32,7 @@ class OneToManyAssociationBuilder extends AssociationBuilder
/**
* @param array $fieldNames
*
* @return OneToManyAssociationBuilder
* @return static
*/
public function setOrderBy(array $fieldNames)
{
@@ -44,7 +44,7 @@ class OneToManyAssociationBuilder extends AssociationBuilder
/**
* @param string $fieldName
*
* @return OneToManyAssociationBuilder
* @return static
*/
public function setIndexBy($fieldName)
{

View File

@@ -31,6 +31,7 @@ use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory;
use Doctrine\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Persistence\Mapping\ReflectionService;
use ReflectionClass;
use ReflectionException;
use function assert;
use function interface_exists;
@@ -278,6 +279,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
if ( ! $class->discriminatorColumn) {
throw MappingException::missingDiscriminatorColumn($class->name);
}
foreach ($class->subClasses as $subClass) {
if ((new ReflectionClass($subClass))->name !== $subClass) {
throw MappingException::invalidClassInDiscriminatorMap($subClass, $class->name);
}
}
}
} else if ($class->isMappedSuperclass && $class->name == $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
// second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy

View File

@@ -28,7 +28,10 @@ use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\ReflectionService;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionProperty;
use RuntimeException;
use function array_key_exists;
use function explode;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
@@ -394,6 +397,8 @@ class ClassMetadataInfo implements ClassMetadata
* Whether a unique constraint should be generated for the column.
*
* @var array
*
* @psalm-var array<string, array{type: string, fieldName: string, columnName: string, inherited: class-string}>
*/
public $fieldMappings = [];
@@ -641,7 +646,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* The ReflectionProperty instances of the mapped class.
*
* @var \ReflectionProperty[]
* @var ReflectionProperty[]|null[]
*/
public $reflFields = [];
@@ -668,7 +673,9 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Gets the ReflectionProperties of the mapped class.
*
* @return array An array of ReflectionProperty instances.
* @return ReflectionProperty[]|null[] An array of ReflectionProperty instances.
*
* @psalm-return array<ReflectionProperty|null>
*/
public function getReflectionProperties()
{
@@ -680,7 +687,7 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param string $name
*
* @return \ReflectionProperty
* @return ReflectionProperty
*/
public function getReflectionProperty($name)
{
@@ -690,7 +697,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Gets the ReflectionProperty for the single identifier field.
*
* @return \ReflectionProperty
* @return ReflectionProperty
*
* @throws BadMethodCallException If the class has a composite identifier.
*/
@@ -806,7 +813,7 @@ class ClassMetadataInfo implements ClassMetadata
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
* @return array The names of all the fields that should be serialized.
* @return string[] The names of all the fields that should be serialized.
*/
public function __sleep()
{
@@ -1097,7 +1104,10 @@ class ClassMetadataInfo implements ClassMetadata
* @param string $fieldName
* @param array $cache
*
* @return array
* @return mixed[]
*
* @psalm-param array{usage: mixed, region: mixed} $cache
* @psalm-return array{usage: mixed, region: mixed}
*/
public function getAssociationCacheDefaults($fieldName, array $cache)
{
@@ -1446,9 +1456,25 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping.
*
* @return array The updated mapping.
* @return mixed[] The updated mapping.
*
* @throws MappingException If something is wrong with the mapping.
*
* @psalm-return array{
* mappedBy: mixed,
* inversedBy: mixed,
* isOwningSide: bool,
* sourceEntity: string,
* targetEntity: string,
* fieldName: mixed,
* fetch: mixed,
* cascade: array<array-key,string>,
* isCascadeRemove: bool,
* isCascadePersist: bool,
* isCascadeRefresh: bool,
* isCascadeMerge: bool,
* isCascadeDetach: bool
* }
*/
protected function _validateAndCompleteAssociationMapping(array $mapping)
{
@@ -1566,10 +1592,12 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping to validate & complete.
*
* @return array The validated & completed mapping.
* @return mixed[] The validated & completed mapping.
*
* @throws RuntimeException
* @throws MappingException
*
* @psalm-return array{isOwningSide: mixed, orphanRemoval: bool, isCascadeRemove: bool}
*/
protected function _validateAndCompleteOneToOneMapping(array $mapping)
{
@@ -1657,10 +1685,27 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping to validate and complete.
*
* @return array The validated and completed mapping.
* @return mixed[] The validated and completed mapping.
*
* @throws MappingException
* @throws InvalidArgumentException
*
* @psalm-return array{
* mappedBy: mixed,
* inversedBy: mixed,
* isOwningSide: bool,
* sourceEntity: string,
* targetEntity: string,
* fieldName: mixed,
* fetch: int|mixed,
* cascade: array<array-key,string>,
* isCascadeRemove: bool,
* isCascadePersist: bool,
* isCascadeRefresh: bool,
* isCascadeMerge: bool,
* isCascadeDetach: bool,
* orphanRemoval: bool
* }
*/
protected function _validateAndCompleteOneToManyMapping(array $mapping)
{
@@ -1684,9 +1729,11 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping to validate & complete.
*
* @return array The validated & completed mapping.
* @return mixed[] The validated & completed mapping.
*
* @throws \InvalidArgumentException
*
* @psalm-return array{isOwningSide: mixed, orphanRemoval: bool}
*/
protected function _validateAndCompleteManyToManyMapping(array $mapping)
{
@@ -1863,7 +1910,9 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array|null $fieldNames
*
* @return array
* @return mixed[]
*
* @psalm-return list<string>
*/
public function getColumnNames(array $fieldNames = null)
{
@@ -2218,6 +2267,12 @@ class ClassMetadataInfo implements ClassMetadata
throw MappingException::invalidOverrideFieldType($this->name, $fieldName);
}
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// The contained 'inherited' information was accidentally deleted by the unset() call below.
if (array_key_exists('inherited', $this->fieldMappings[$fieldName])) {
$overrideMapping['inherited'] = $this->fieldMappings[$fieldName]['inherited'];
}
unset($this->fieldMappings[$fieldName]);
unset($this->fieldNames[$mapping['columnName']]);
unset($this->columnNames[$mapping['fieldName']]);
@@ -2299,7 +2354,7 @@ class ClassMetadataInfo implements ClassMetadata
if (isset($table['name'])) {
// Split schema and table name from a table name like "myschema.mytable"
if (strpos($table['name'], '.') !== false) {
list($this->table['schema'], $table['name']) = explode('.', $table['name'], 2);
[$this->table['schema'], $table['name']] = explode('.', $table['name'], 2);
}
if ($table['name'][0] === '`') {
@@ -2525,7 +2580,7 @@ class ClassMetadataInfo implements ClassMetadata
if (!isset($field['column'])) {
$fieldName = $field['name'];
if (strpos($fieldName, '.')) {
list(, $fieldName) = explode('.', $fieldName);
[, $fieldName] = explode('.', $fieldName);
}
$resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName;

View File

@@ -40,7 +40,8 @@ use function interface_exists;
class AnnotationDriver extends AbstractAnnotationDriver
{
/**
* {@inheritDoc}
* @var int[]
* @psalm-var array<class-string, int>
*/
protected $entityAnnotationClasses = [
Mapping\Entity::class => 1,
@@ -274,7 +275,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
}
// Evaluate annotations on properties/fields
/* @var $property \ReflectionProperty */
foreach ($class->getProperties() as $property) {
if ($metadata->isMappedSuperclass && ! $property->isPrivate()
||
@@ -505,7 +505,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
$hasMapping = false;
$listenerClass = new \ReflectionClass($listenerClassName);
/* @var $method \ReflectionMethod */
foreach ($listenerClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
// find method callbacks.
$callbacks = $this->getMethodCallbacks($method);
@@ -525,7 +524,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
// Evaluate @HasLifecycleCallbacks annotation
if (isset($classAnnotations[Mapping\HasLifecycleCallbacks::class])) {
/* @var $method \ReflectionMethod */
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
foreach ($this->getMethodCallbacks($method) as $value) {
$metadata->addLifecycleCallback($value[0], $value[1]);
@@ -558,7 +556,7 @@ class AnnotationDriver extends AbstractAnnotationDriver
*
* @param \ReflectionMethod $method
*
* @return array
* @return callable[]
*/
private function getMethodCallbacks(\ReflectionMethod $method)
{
@@ -606,7 +604,17 @@ class AnnotationDriver extends AbstractAnnotationDriver
* Parse the given JoinColumn as array
*
* @param Mapping\JoinColumn $joinColumn
* @return array
*
* @return mixed[]
*
* @psalm-return array{
* name: string,
* unique: bool,
* nullable: bool,
* onDelete: mixed,
* columnDefinition: string,
* referencedColumnName: string
* }
*/
private function joinColumnToArray(Mapping\JoinColumn $joinColumn)
{
@@ -626,7 +634,20 @@ class AnnotationDriver extends AbstractAnnotationDriver
* @param string $fieldName
* @param Mapping\Column $column
*
* @return array
* @return mixed[]
*
* @psalm-return array{
* fieldName: string,
* type: mixed,
* scale: int,
* length: int,
* unique: bool,
* nullable: bool,
* precision: int,
* options?: mixed[],
* columnName?: string,
* columnDefinition?: string
* }
*/
private function columnToArray($fieldName, Mapping\Column $column)
{

View File

@@ -21,6 +21,7 @@ namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Inflector\Inflector;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\Column;
@@ -388,6 +389,22 @@ class DatabaseDriver implements MappingDriver
* @param \Doctrine\DBAL\Schema\Column $column
*
* @return array
*
* @psalm-return array{
* fieldName: string,
* columnName: string,
* type: string,
* nullable: bool,
* options?: array{
* unsigned?: bool,
* fixed?: bool,
* comment?: string,
* default?: string
* },
* precision?: int,
* scale?: int,
* length?: int|null
* }
*/
private function buildFieldMapping($tableName, Column $column)
{
@@ -488,7 +505,9 @@ class DatabaseDriver implements MappingDriver
*
* @param \Doctrine\DBAL\Schema\Table $table
*
* @return array
* @return ForeignKeyConstraint[]
*
* @psalm-return array<string, ForeignKeyConstraint>
*/
private function getTableForeignKeys(Table $table)
{
@@ -502,7 +521,7 @@ class DatabaseDriver implements MappingDriver
*
* @param \Doctrine\DBAL\Schema\Table $table
*
* @return array
* @return string[]
*/
private function getTablePrimaryKeys(Table $table)
{

View File

@@ -671,13 +671,12 @@ class XmlDriver extends FileDriver
*
* @param SimpleXMLElement $options The XML element.
*
* @return array The options array.
* @return mixed[] The options array.
*/
private function _parseOptions(SimpleXMLElement $options)
{
$array = [];
/* @var $option SimpleXMLElement */
foreach ($options as $option) {
if ($option->count()) {
$value = $this->_parseOptions($option->children());
@@ -706,7 +705,16 @@ class XmlDriver extends FileDriver
*
* @param SimpleXMLElement $joinColumnElement The XML element.
*
* @return array The mapping array.
* @return mixed[] The mapping array.
*
* @psalm-return array{
* name: string,
* referencedColumnName: string,
* unique?: bool,
* nullable?: bool,
* onDelete?: string,
* columnDefinition?: string
* }
*/
private function joinColumnToArray(SimpleXMLElement $joinColumnElement)
{
@@ -735,12 +743,24 @@ class XmlDriver extends FileDriver
}
/**
* Parses the given field as array.
*
* @param SimpleXMLElement $fieldMapping
*
* @return array
*/
* Parses the given field as array.
*
* @return mixed[]
*
* @psalm-return array{
* fieldName: string,
* type?: string,
* columnName?: string,
* length?: int,
* precision?: int,
* scale?: int,
* unique?: bool,
* nullable?: bool,
* version?: bool,
* columnDefinition?: string,
* options?: array
* }
*/
private function columnToArray(SimpleXMLElement $fieldMapping)
{
$mapping = [
@@ -795,7 +815,9 @@ class XmlDriver extends FileDriver
*
* @param SimpleXMLElement $cacheMapping
*
* @return array
* @return mixed[]
*
* @psalm-return array{usage: mixed, region: string|null}
*/
private function cacheToArray(SimpleXMLElement $cacheMapping)
{
@@ -821,12 +843,13 @@ class XmlDriver extends FileDriver
*
* @param SimpleXMLElement $cascadeElement The cascade element.
*
* @return array The list of cascade options.
* @return string[] The list of cascade options.
*
* @psalm-return list<string>
*/
private function _getCascadeMappings(SimpleXMLElement $cascadeElement)
{
$cascades = [];
/* @var $action SimpleXmlElement */
foreach ($cascadeElement->children() as $action) {
// According to the JPA specifications, XML uses "cascade-persist"
// instead of "persist". Here, both variations

View File

@@ -684,7 +684,17 @@ class YamlDriver extends FileDriver
*
* @param array $joinColumnElement The array join column element.
*
* @return array The mapping array.
* @return mixed[] The mapping array.
*
* @psalm-return array{
* referencedColumnName?: string,
* name?: string,
* fieldName?: string,
* unique?: bool,
* nullable?: bool,
* onDelete?: mixed,
* columnDefinition?: mixed
* }
*/
private function joinColumnToArray($joinColumnElement)
{
@@ -726,7 +736,21 @@ class YamlDriver extends FileDriver
* @param string $fieldName
* @param array $column
*
* @return array
* @return mixed[]
*
* @psalm-return array{
* fieldName: string,
* type?: string,
* columnName?: mixed,
* length?: mixed,
* precision?: mixed,
* scale?: mixed,
* unique?: bool,
* options?: mixed,
* nullable?: mixed,
* version?: mixed,
* columnDefinition?: mixed
* }
*/
private function columnToArray($fieldName, $column)
{
@@ -787,9 +811,12 @@ class YamlDriver extends FileDriver
/**
* Parse / Normalize the cache configuration
*
* @param array $cacheMapping
* @param mixed[] $cacheMapping
*
* @return array
* @return mixed[]
*
* @psalm-param array{usage: mixed, region: null|string} $cacheMapping
* @psalm-return array{usage: mixed, region: null|string}
*/
private function cacheToArray($cacheMapping)
{

View File

@@ -52,9 +52,11 @@ final class ReflectionPropertiesGetter
}
/**
* @param $className
* @param string $className
*
* @return ReflectionProperty[] indexed by property internal name
*
* @psalm-param class-string $className
*/
public function getProperties($className)
{
@@ -79,8 +81,10 @@ final class ReflectionPropertiesGetter
* @param string $className
*
* @return ReflectionClass[]
*
* @psalm-return list<ReflectionClass>
*/
private function getHierarchyClasses($className)
private function getHierarchyClasses($className) : array
{
$classes = [];
$parentClassName = $className;
@@ -97,13 +101,17 @@ final class ReflectionPropertiesGetter
return $classes;
}
// phpcs:disable SlevomatCodingStandard.Classes.UnusedPrivateElements.UnusedMethod
/**
* @param ReflectionClass $reflectionClass
*
* @return ReflectionProperty[]
*
* @psalm-return array<string, ReflectionProperty>
*/
private function getClassProperties(ReflectionClass $reflectionClass)
private function getClassProperties(ReflectionClass $reflectionClass) : array
{
// phpcs:enable SlevomatCodingStandard.Classes.UnusedPrivateElements.UnusedMethod
$properties = $reflectionClass->getProperties();
return array_filter(

View File

@@ -37,9 +37,9 @@ final class NativeQuery extends AbstractQuery
*
* @param string $sql
*
* @return NativeQuery This query instance.
* @return self This query instance.
*/
public function setSQL($sql)
public function setSQL($sql) : self
{
$this->_sql = $sql;

View File

@@ -110,7 +110,7 @@ class ORMException extends Exception
* @param string $given
* @param string $expected
*
* @return \Doctrine\ORM\ORMInvalidArgumentException
* @return \Doctrine\ORM\ORMException
*/
public static function unexpectedAssociationValue($class, $association, $given, $expected)
{

View File

@@ -36,7 +36,7 @@ class OptimisticLockException extends ORMException
/**
* @param string $msg
* @param object $entity
* @param object|null $entity
*/
public function __construct($msg, $entity)
{

View File

@@ -337,6 +337,8 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
/**
* {@inheritdoc}
*
* @return object
*/
public function remove($key)
{
@@ -510,6 +512,8 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
/**
* {@inheritdoc}
*
* @return object
*/
public function offsetUnset($offset)
{
@@ -569,9 +573,11 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
* Internal note: Tried to implement Serializable first but that did not work well
* with circular references. This solution seems simpler and works well.
*
* @return array
* @return string[]
*
* @psalm-return array{0: string, 1: string}
*/
public function __sleep()
public function __sleep() : array
{
return ['collection', 'initialized'];
}

View File

@@ -68,8 +68,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
return; // ignore inverse side
}
list($deleteSql, $deleteTypes) = $this->getDeleteRowSQL($collection);
list($insertSql, $insertTypes) = $this->getInsertRowSQL($collection);
[$deleteSql, $deleteTypes] = $this->getDeleteRowSQL($collection);
[$insertSql, $insertTypes] = $this->getInsertRowSQL($collection);
foreach ($collection->getDeleteDiff() as $element) {
$this->conn->executeUpdate(
@@ -136,7 +136,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$types[] = PersisterHelper::getTypeOfColumn($referencedName, $sourceClass, $this->em);
}
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
[$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($mapping);
if ($filterSql) {
$conditions[] = $filterSql;
@@ -188,7 +188,11 @@ class ManyToManyPersister extends AbstractCollectionPersister
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
}
list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictionsWithKey($collection, $key, true);
[$quotedJoinTable, $whereClauses, $params, $types] = $this->getJoinTableRestrictionsWithKey(
$collection,
$key,
true
);
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
@@ -204,7 +208,11 @@ class ManyToManyPersister extends AbstractCollectionPersister
return false;
}
list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictions($collection, $element, true);
[$quotedJoinTable, $whereClauses, $params, $types] = $this->getJoinTableRestrictions(
$collection,
$element,
true
);
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
@@ -288,6 +296,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
* @return string[] ordered tuple:
* - JOIN condition to add to the SQL
* - WHERE condition to add to the SQL
*
* @psalm-return array{0: string, 1: string}
*/
public function getFilterSql($mapping)
{
@@ -335,7 +345,9 @@ class ManyToManyPersister extends AbstractCollectionPersister
*
* @param array $mapping
*
* @return array
* @return string[]
*
* @psalm-return list<string>
*/
protected function getOnConditionSQL($mapping)
{
@@ -361,9 +373,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
}
/**
* {@inheritdoc}
*
* @override
* @return string
*/
protected function getDeleteSQL(PersistentCollection $collection)
{
@@ -381,10 +391,9 @@ class ManyToManyPersister extends AbstractCollectionPersister
}
/**
* {@inheritdoc}
*
* Internal note: Order of the parameters must be the same as the order of the columns in getDeleteSql.
* @override
*
* @return mixed[]
*/
protected function getDeleteSQLParameters(PersistentCollection $collection)
{
@@ -416,6 +425,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
*
* @return string[]|string[][] ordered tuple containing the SQL to be executed and an array
* of types for bound parameters
*
* @psalm-return array{0: string, 1: list<string>}
*/
protected function getDeleteRowSQL(PersistentCollection $collection)
{
@@ -452,6 +463,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
* @param mixed $element
*
* @return array
*
* @psalm-return list<mixed>
*/
protected function getDeleteRowSQLParameters(PersistentCollection $collection, $element)
{
@@ -465,6 +478,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
*
* @return string[]|string[][] ordered tuple containing the SQL to be executed and an array
* of types for bound parameters
*
* @psalm-return array{0: string, 1: list<string>}
*/
protected function getInsertRowSQL(PersistentCollection $collection)
{
@@ -503,6 +518,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
* @param mixed $element
*
* @return array
*
* @psalm-return list<mixed>
*/
protected function getInsertRowSQLParameters(PersistentCollection $collection, $element)
{
@@ -516,7 +533,9 @@ class ManyToManyPersister extends AbstractCollectionPersister
* @param \Doctrine\ORM\PersistentCollection $collection
* @param object $element
*
* @return array
* @return mixed[]
*
* @psalm-return list<mixed>
*/
private function collectJoinTableColumnParameters(PersistentCollection $collection, $element)
{
@@ -564,6 +583,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
* - where clauses to be added for filtering
* - parameters to be bound for filtering
* - types of the parameters to be bound for filtering
*
* @psalm-return array{0: string, 1: list<string>, 2: list<mixed>, 3: list<string>}
*/
private function getJoinTableRestrictionsWithKey(PersistentCollection $collection, $key, $addFilters)
{
@@ -628,7 +649,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
}
if ($addFilters) {
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
[$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($filterMapping);
if ($filterSql) {
$quotedJoinTable .= ' ' . $joinTargetEntitySQL;
@@ -649,6 +670,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
* - where clauses to be added for filtering
* - parameters to be bound for filtering
* - types of the parameters to be bound for filtering
*
* @psalm-return array{0: string, 1: list<string>, 2: list<mixed>, 3: list<string>}
*/
private function getJoinTableRestrictions(PersistentCollection $collection, $element, $addFilters)
{
@@ -694,7 +717,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
if ($addFilters) {
$quotedJoinTable .= ' t';
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
[$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($filterMapping);
if ($filterSql) {
$quotedJoinTable .= ' ' . $joinTargetEntitySQL;
@@ -725,7 +748,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$valueVisitor->dispatch($expression);
list(, $types) = $valueVisitor->getParamsAndTypes();
[, $types] = $valueVisitor->getParamsAndTypes();
return $types;
}

View File

@@ -36,6 +36,8 @@ class OneToManyPersister extends AbstractCollectionPersister
{
/**
* {@inheritdoc}
*
* @return int|null
*/
public function delete(PersistentCollection $collection)
{

View File

@@ -37,6 +37,7 @@ use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use Doctrine\ORM\Utility\IdentifierFlattener;
use Doctrine\ORM\Utility\PersisterHelper;
use function array_key_exists;
use function array_map;
use function array_merge;
use function assert;
@@ -360,6 +361,11 @@ class BasicEntityPersister implements EntityPersister
return Type::getType($fieldMapping['type'])->convertToPHPValue($value, $this->platform);
}
/**
* @return int[]|null[]|string[]
*
* @psalm-return list<int|null|string>
*/
private function extractIdentifierTypes(array $id, ClassMetadata $versionedClass) : array
{
$types = [];
@@ -442,14 +448,26 @@ class BasicEntityPersister implements EntityPersister
$types[] = $this->columnTypes[$columnName];
}
$where = [];
$identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
$where = [];
$identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
$quotedClassTableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
foreach ($this->class->identifier as $idField) {
if ( ! isset($this->class->associationMappings[$idField])) {
$params[] = $identifier[$idField];
$types[] = $this->class->fieldMappings[$idField]['type'];
$where[] = $this->quoteStrategy->getColumnName($idField, $this->class, $this->platform);
$params[] = $identifier[$idField];
$types[] = $this->class->fieldMappings[$idField]['type'];
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// This method is called with the updated entity, but with different table names
// (the entity table name or a table name of an inherited entity). In dependence
// of the used table, the identifier name must be adjusted.
$class = $this->class;
if (isset($class->fieldMappings[$idField]['inherited']) && $quotedTableName !== $quotedClassTableName) {
$className = $this->class->fieldMappings[$idField]['inherited'];
$class = $this->em->getClassMetadata($className);
}
$where[] = $this->quoteStrategy->getColumnName($idField, $class, $this->platform);
continue;
}
@@ -601,7 +619,9 @@ class BasicEntityPersister implements EntityPersister
*
* @param object $entity The entity for which to prepare the data.
*
* @return array The prepared data.
* @return mixed[][] The prepared data.
*
* @psalm-return array<string, array<array-key, mixed|null>>
*/
protected function prepareUpdateData($entity)
{
@@ -625,7 +645,18 @@ class BasicEntityPersister implements EntityPersister
$newVal = $change[1];
if ( ! isset($this->class->associationMappings[$field])) {
$fieldMapping = $this->class->fieldMappings[$field];
$class = $this->class;
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// Get the correct class metadata
foreach ($class->parentClasses as $parentClassName) {
$parentClass = $this->em->getClassMetadata($parentClassName);
if (array_key_exists($field, $parentClass->fieldMappings)) {
$class = $parentClass;
}
}
$fieldMapping = $class->fieldMappings[$field];
$columnName = $fieldMapping['columnName'];
$this->columnTypes[$columnName] = $fieldMapping['type'];
@@ -688,9 +719,11 @@ class BasicEntityPersister implements EntityPersister
*
* @param object $entity The entity for which to prepare the data.
*
* @return array The prepared data for the tables to update.
* @return mixed[][] The prepared data for the tables to update.
*
* @see prepareUpdateData
*
* @psalm-return array<string, mixed[]>
*/
protected function prepareInsertData($entity)
{
@@ -713,7 +746,7 @@ class BasicEntityPersister implements EntityPersister
$this->switchPersisterContext(null, $limit);
$sql = $this->getSelectSQL($criteria, $assoc, $lockMode, $limit, null, $orderBy);
list($params, $types) = $this->expandParameters($criteria);
[$params, $types] = $this->expandParameters($criteria);
$stmt = $this->conn->executeQuery($sql, $params, $types);
if ($entity !== null) {
@@ -805,7 +838,7 @@ class BasicEntityPersister implements EntityPersister
public function refresh(array $id, $entity, $lockMode = null)
{
$sql = $this->getSelectSQL($id, null, $lockMode);
list($params, $types) = $this->expandParameters($id);
[$params, $types] = $this->expandParameters($id);
$stmt = $this->conn->executeQuery($sql, $params, $types);
$hydrator = $this->em->newHydrator(Query::HYDRATE_OBJECT);
@@ -819,7 +852,7 @@ class BasicEntityPersister implements EntityPersister
{
$sql = $this->getCountSQL($criteria);
list($params, $types) = ($criteria instanceof Criteria)
[$params, $types] = $criteria instanceof Criteria
? $this->expandCriteriaParameters($criteria)
: $this->expandParameters($criteria);
@@ -836,7 +869,7 @@ class BasicEntityPersister implements EntityPersister
$offset = $criteria->getFirstResult();
$query = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy);
list($params, $types) = $this->expandCriteriaParameters($criteria);
[$params, $types] = $this->expandCriteriaParameters($criteria);
$stmt = $this->conn->executeQuery($query, $params, $types);
$hydrator = $this->em->newHydrator(($this->currentPersisterContext->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
@@ -862,14 +895,14 @@ class BasicEntityPersister implements EntityPersister
$valueVisitor->dispatch($expression);
list($params, $types) = $valueVisitor->getParamsAndTypes();
[$params, $types] = $valueVisitor->getParamsAndTypes();
foreach ($params as $param) {
$sqlParams = array_merge($sqlParams, $this->getValues($param));
}
foreach ($types as $type) {
list ($field, $value) = $type;
[$field, $value] = $type;
$sqlTypes = array_merge($sqlTypes, $this->getTypes($field, $value, $this->class));
}
@@ -884,7 +917,7 @@ class BasicEntityPersister implements EntityPersister
$this->switchPersisterContext($offset, $limit);
$sql = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy);
list($params, $types) = $this->expandParameters($criteria);
[$params, $types] = $this->expandParameters($criteria);
$stmt = $this->conn->executeQuery($sql, $params, $types);
$hydrator = $this->em->newHydrator(($this->currentPersisterContext->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
@@ -954,11 +987,11 @@ class BasicEntityPersister implements EntityPersister
/**
* {@inheritdoc}
*/
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
{
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity);
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
return $this->loadCollectionFromStatement($assoc, $stmt, $collection);
}
/**
@@ -1029,7 +1062,7 @@ class BasicEntityPersister implements EntityPersister
}
$sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset);
list($params, $types) = $this->expandToManyParameters($parameters);
[$params, $types] = $this->expandToManyParameters($parameters);
return $this->conn->executeQuery($sql, $params, $types);
}
@@ -1133,7 +1166,7 @@ class BasicEntityPersister implements EntityPersister
*
* @throws \Doctrine\ORM\ORMException
*/
protected final function getOrderBySQL(array $orderBy, $baseTableAlias)
final protected function getOrderBySQL(array $orderBy, $baseTableAlias) : string
{
$orderByList = [];
@@ -1418,7 +1451,9 @@ class BasicEntityPersister implements EntityPersister
* Subclasses should override this method to alter or change the list of
* columns placed in the INSERT statements used by the persister.
*
* @return array The list of columns.
* @return string[] The list of columns.
*
* @psalm-return list<string>
*/
protected function getInsertColumnList()
{
@@ -1535,7 +1570,7 @@ class BasicEntityPersister implements EntityPersister
. $where
. $lockSql;
list($params, $types) = $this->expandParameters($criteria);
[$params, $types] = $this->expandParameters($criteria);
$this->conn->executeQuery($sql, $params, $types);
}
@@ -1543,7 +1578,7 @@ class BasicEntityPersister implements EntityPersister
/**
* Gets the FROM and optionally JOIN conditions to lock the entity managed by this persister.
*
* @param integer $lockMode One of the Doctrine\DBAL\LockMode::* constants.
* @param int|null $lockMode One of the Doctrine\DBAL\LockMode::* constants.
*
* @return string
*/
@@ -1655,15 +1690,23 @@ class BasicEntityPersister implements EntityPersister
* @return string[]
*
* @throws \Doctrine\ORM\ORMException
*
* @psalm-return list<string>
*/
private function getSelectConditionStatementColumnSQL($field, $assoc = null)
{
if (isset($this->class->fieldMappings[$field])) {
$className = (isset($this->class->fieldMappings[$field]['inherited']))
? $this->class->fieldMappings[$field]['inherited']
: $this->class->name;
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// Use the correct metadata and name for the id column
if (isset($this->class->fieldMappings[$field]['inherited'])) {
$className = $this->class->fieldMappings[$field]['inherited'];
$class = $this->em->getClassMetadata($className);
} else {
$className = $this->class->name;
$class = $this->class;
}
return [$this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getColumnName($field, $this->class, $this->platform)];
return [$this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getColumnName($field, $class, $this->platform)];
}
if (isset($this->class->associationMappings[$field])) {
@@ -1752,11 +1795,11 @@ class BasicEntityPersister implements EntityPersister
/**
* {@inheritdoc}
*/
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
{
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity);
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
return $this->loadCollectionFromStatement($assoc, $stmt, $collection);
}
/**
@@ -1812,7 +1855,7 @@ class BasicEntityPersister implements EntityPersister
}
$sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset);
list($params, $types) = $this->expandToManyParameters($parameters);
[$params, $types] = $this->expandToManyParameters($parameters);
return $this->conn->executeQuery($sql, $params, $types);
}
@@ -1846,8 +1889,9 @@ class BasicEntityPersister implements EntityPersister
* - value to be bound
* - class to which the field belongs to
*
* @return mixed[][]
*
* @return array
* @psalm-return array{0: array, 1: list<mixed>}
*/
private function expandToManyParameters($criteria)
{
@@ -1873,9 +1917,11 @@ class BasicEntityPersister implements EntityPersister
* @param mixed $value
* @param ClassMetadata $class
*
* @return array
* @return int[]|null[]|string[]
*
* @throws \Doctrine\ORM\Query\QueryException
*
* @psalm-return list<int|null|string>
*/
private function getTypes($field, $value, ClassMetadata $class)
{
@@ -1988,11 +2034,11 @@ class BasicEntityPersister implements EntityPersister
. $this->getLockTablesSql(null)
. ' WHERE ' . $this->getSelectConditionSQL($criteria);
list($params, $types) = $this->expandParameters($criteria);
[$params, $types] = $this->expandParameters($criteria);
if (null !== $extraConditions) {
$sql .= ' AND ' . $this->getSelectConditionCriteriaSQL($extraConditions);
list($criteriaParams, $criteriaTypes) = $this->expandCriteriaParameters($extraConditions);
[$criteriaParams, $criteriaTypes] = $this->expandCriteriaParameters($extraConditions);
$params = array_merge($params, $criteriaParams);
$types = array_merge($types, $criteriaTypes);
@@ -2025,7 +2071,9 @@ class BasicEntityPersister implements EntityPersister
}
/**
* {@inheritdoc}
* @param string $columnName
*
* @return string
*/
public function getSQLColumnAlias($columnName)
{

View File

@@ -86,7 +86,7 @@ interface EntityPersister
/**
* Expands the parameters from the given criteria and use the correct binding types if found.
*
* @param $criteria
* @param string[] $criteria
*
* @return array
*/

View File

@@ -26,6 +26,8 @@ use Doctrine\DBAL\Types\Type;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Utility\PersisterHelper;
use function array_combine;
use function array_reverse;
/**
* The joined subclass persister maps a single entity instance to several tables in the
@@ -271,35 +273,42 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
public function delete($entity)
{
$identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
$id = array_combine($this->class->getIdentifierColumnNames(), $identifier);
$this->deleteJoinTableRecords($identifier);
// If the database platform supports FKs, just
// delete the row from the root table. Cascades do the rest.
if ($this->platform->supportsForeignKeyConstraints()) {
$rootClass = $this->em->getClassMetadata($this->class->rootEntityName);
$rootTable = $this->quoteStrategy->getTableName($rootClass, $this->platform);
$rootTypes = $this->getClassIdentifiersTypes($rootClass);
return (bool) $this->conn->delete($rootTable, $id, $rootTypes);
}
// Delete from all tables individually, starting from this class' table up to the root table.
$rootTable = $this->quoteStrategy->getTableName($this->class, $this->platform);
$rootTypes = $this->getClassIdentifiersTypes($this->class);
$affectedRows = $this->conn->delete($rootTable, $id, $rootTypes);
foreach ($this->class->parentClasses as $parentClass) {
// Delete parent entries in reverse order (root first, until the direct parent of the current class).
//
// If foreign key are supported (and set as well as active), the first deletion will cascade and the
// following queries won't delete anything, but it's better not to rely on a possible foreign key
// functionality which cannot be checked here (foreign keys can be missing or disabled although
// supported in general).
//
// On the other hand the supportsForeignKeyConstraints() method of the platform is also not reliable
// when it returns false, because it only means that Doctrine\DBAL doesn't support foreign keys for
// this platform, but they may be set in an existing database structure or added manually, so the
// previous order of deletion (current class to root) would have failed - this could i.e. happen with
// SQLite where foreign keys are theoretically possible but not supported by DBAL.
$deleted = false;
foreach (array_reverse($this->class->parentClasses) as $parentClass) {
$parentMetadata = $this->em->getClassMetadata($parentClass);
$parentTable = $this->quoteStrategy->getTableName($parentMetadata, $this->platform);
$parentTypes = $this->getClassIdentifiersTypes($parentMetadata);
$parentId = array_combine($parentMetadata->getIdentifierColumnNames(), $identifier);
$this->conn->delete($parentTable, $id, $parentTypes);
$affectedRows = $this->conn->delete($parentTable, $parentId, $parentTypes);
$deleted = $deleted ?: ($affectedRows > 0);
}
return (bool) $affectedRows;
// Now delete the entries from the current class (if not deleted automatically
// because of a foreign key).
$currentTable = $this->quoteStrategy->getTableName($this->class, $this->platform);
$currentTypes = $this->getClassIdentifiersTypes($this->class);
$currentId = array_combine($this->class->getIdentifierColumnNames(), $identifier);
$affectedRows = $this->conn->delete($currentTable, $currentId, $currentTypes);
$deleted = $deleted ?: ($affectedRows > 0);
return $deleted;
}
/**
@@ -412,8 +421,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
$parentClass = $this->em->getClassMetadata($parentClassName);
$joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON ';
foreach ($identifierColumns as $idColumn) {
$conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// Use the correct name for the id column as named in the parent class.
$parentIdentifierColumns = $parentClass->getIdentifierColumnNames();
foreach ($identifierColumns as $index => $idColumn) {
$conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $parentIdentifierColumns[$index];
}
$joinSql .= implode(' AND ', $conditions);
@@ -589,9 +601,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
$tableAlias = $this->getSQLTableAlias($parentClassName);
$joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON ';
foreach ($identifierColumn as $idColumn) {
$conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// Use the correct name for the id column as named in the parent class.
$parentIdentifierColumn = $parentClass->getIdentifierColumnNames();
foreach ($identifierColumn as $index => $idColumn) {
$conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $parentIdentifierColumn[$index];
}
$joinSql .= implode(' AND ', $conditions);
@@ -604,8 +618,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
$tableAlias = $this->getSQLTableAlias($subClassName);
$joinSql .= ' LEFT JOIN ' . $this->quoteStrategy->getTableName($subClass, $this->platform) . ' ' . $tableAlias . ' ON ';
foreach ($identifierColumn as $idColumn) {
$conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// Use the correct name for the id column as named in the parent class.
$subClassIdentifierColumn = $subClass->getIdentifierColumnNames();
foreach ($identifierColumn as $index => $idColumn) {
$conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $subClassIdentifierColumn[$index];
}
$joinSql .= implode(' AND ', $conditions);

View File

@@ -93,7 +93,9 @@ class SqlValueVisitor extends ExpressionVisitor
/**
* Returns the Parameters and Types necessary for matching the last visited expression.
*
* @return array
* @return mixed[][]
*
* @psalm-return array{0: array, 1: array}
*/
public function getParamsAndTypes()
{

View File

@@ -122,6 +122,8 @@ class ProxyFactory extends AbstractProxyFactory
* @return \Closure
*
* @throws \Doctrine\ORM\EntityNotFoundException
*
* @psalm-return \Closure(BaseProxy):void
*/
private function createInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister)
{
@@ -173,6 +175,8 @@ class ProxyFactory extends AbstractProxyFactory
* @return \Closure
*
* @throws \Doctrine\ORM\EntityNotFoundException
*
* @psalm-return \Closure(BaseProxy):void
*/
private function createCloner(ClassMetadata $classMetadata, EntityPersister $entityPersister)
{

View File

@@ -22,6 +22,9 @@ namespace Doctrine\ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\AST\DeleteStatement;
use Doctrine\ORM\Query\AST\SelectStatement;
use Doctrine\ORM\Query\AST\UpdateStatement;
use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Query\ParameterTypeInferer;
@@ -213,9 +216,7 @@ final class Query extends AbstractQuery
/**
* Returns the corresponding AST for this DQL query.
*
* @return \Doctrine\ORM\Query\AST\SelectStatement |
* \Doctrine\ORM\Query\AST\UpdateStatement |
* \Doctrine\ORM\Query\AST\DeleteStatement
* @return SelectStatement|UpdateStatement|DeleteStatement
*/
public function getAST()
{
@@ -325,7 +326,7 @@ final class Query extends AbstractQuery
$this->evictEntityCacheRegion();
}
list($sqlParams, $types) = $this->processParameterMappings($paramMappings);
[$sqlParams, $types] = $this->processParameterMappings($paramMappings);
$this->evictResultSetCache(
$executor,
@@ -364,11 +365,11 @@ final class Query extends AbstractQuery
{
$AST = $this->getAST();
if ($AST instanceof \Doctrine\ORM\Query\AST\SelectStatement) {
if ($AST instanceof SelectStatement) {
throw new QueryException('The hint "HINT_CACHE_EVICT" is not valid for select statements.');
}
$className = ($AST instanceof \Doctrine\ORM\Query\AST\DeleteStatement)
$className = $AST instanceof DeleteStatement
? $AST->deleteClause->abstractSchemaName
: $AST->updateClause->abstractSchemaName;
@@ -380,11 +381,13 @@ final class Query extends AbstractQuery
*
* @param array $paramMappings
*
* @return array
* @return mixed[][]
*
* @throws Query\QueryException
*
* @psalm-return array{0: list<mixed>, 1: array}
*/
private function processParameterMappings($paramMappings)
private function processParameterMappings($paramMappings) : array
{
$sqlParams = [];
$types = [];
@@ -429,7 +432,11 @@ final class Query extends AbstractQuery
return [$sqlParams, $types];
}
/** @return mixed[] tuple of (value, type) */
/**
* @return mixed[] tuple of (value, type)
*
* @psalm-return array{0: mixed, 1: mixed}
*/
private function resolveParameterValue(Parameter $parameter) : array
{
if ($parameter->typeWasSpecified()) {
@@ -466,9 +473,9 @@ final class Query extends AbstractQuery
*
* @param \Doctrine\Common\Cache\Cache|null $queryCache Cache driver.
*
* @return Query This query instance.
* @return self This query instance.
*/
public function setQueryCacheDriver($queryCache)
public function setQueryCacheDriver($queryCache) : self
{
$this->_queryCache = $queryCache;
@@ -480,9 +487,9 @@ final class Query extends AbstractQuery
*
* @param boolean $bool
*
* @return Query This query instance.
* @return self This query instance.
*/
public function useQueryCache($bool)
public function useQueryCache($bool) : self
{
$this->_useQueryCache = $bool;
@@ -509,9 +516,9 @@ final class Query extends AbstractQuery
*
* @param integer $timeToLive How long the cache entry is valid.
*
* @return Query This query instance.
* @return self This query instance.
*/
public function setQueryCacheLifetime($timeToLive)
public function setQueryCacheLifetime($timeToLive) : self
{
if ($timeToLive !== null) {
$timeToLive = (int) $timeToLive;
@@ -537,9 +544,9 @@ final class Query extends AbstractQuery
*
* @param boolean $expire Whether or not to force query cache expiration.
*
* @return Query This query instance.
* @return self This query instance.
*/
public function expireQueryCache($expire = true)
public function expireQueryCache($expire = true) : self
{
$this->_expireQueryCache = $expire;
@@ -571,10 +578,8 @@ final class Query extends AbstractQuery
* Sets a DQL query string.
*
* @param string $dqlQuery DQL Query.
*
* @return \Doctrine\ORM\AbstractQuery
*/
public function setDQL($dqlQuery)
public function setDQL($dqlQuery) : self
{
if ($dqlQuery !== null) {
$this->_dql = $dqlQuery;
@@ -626,9 +631,9 @@ final class Query extends AbstractQuery
*
* @param int|null $firstResult The first result to return.
*
* @return Query This query object.
* @return self This query object.
*/
public function setFirstResult($firstResult)
public function setFirstResult($firstResult) : self
{
$this->_firstResult = $firstResult;
$this->_state = self::STATE_DIRTY;
@@ -652,9 +657,9 @@ final class Query extends AbstractQuery
*
* @param integer|null $maxResults
*
* @return Query This query object.
* @return self This query object.
*/
public function setMaxResults($maxResults)
public function setMaxResults($maxResults) : self
{
$this->_maxResults = $maxResults;
$this->_state = self::STATE_DIRTY;
@@ -716,11 +721,9 @@ final class Query extends AbstractQuery
*
* @param int $lockMode
*
* @return Query
*
* @throws TransactionRequiredException
*/
public function setLockMode($lockMode)
public function setLockMode($lockMode) : self
{
if (in_array($lockMode, [LockMode::NONE, LockMode::PESSIMISTIC_READ, LockMode::PESSIMISTIC_WRITE], true)) {
if ( ! $this->_em->getConnection()->isTransactionActive()) {

View File

@@ -105,7 +105,7 @@ class TrimFunction extends FunctionNode
}
/**
* @return integer
* @return int
*/
private function getTrimMode()
{

View File

@@ -32,7 +32,7 @@ namespace Doctrine\ORM\Query\AST;
class SimpleSelectExpression extends Node
{
/**
* @var Node
* @var Node|string
*/
public $expression;
@@ -42,7 +42,7 @@ class SimpleSelectExpression extends Node
public $fieldIdentificationVariable;
/**
* @param Node $expression
* @param Node|string $expression
*/
public function __construct($expression)
{

View File

@@ -31,7 +31,7 @@ namespace Doctrine\ORM\Query\AST;
class WhereClause extends Node
{
/**
* @var ConditionalExpression
* @var ConditionalExpression|ConditionalTerm
*/
public $conditionalExpression;

View File

@@ -34,7 +34,7 @@ use Doctrine\DBAL\Cache\QueryCacheProfile;
abstract class AbstractSqlExecutor
{
/**
* @var array
* @var mixed[]|string
*/
protected $_sqlStatements;
@@ -46,7 +46,7 @@ abstract class AbstractSqlExecutor
/**
* Gets the SQL statements that are executed by the executor.
*
* @return array All the SQL update statements.
* @return mixed[]|string All the SQL update statements.
*/
public function getSqlStatements()
{

View File

@@ -22,6 +22,8 @@ namespace Doctrine\ORM\Query\Exec;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Query\AST;
use Doctrine\ORM\Query\AST\DeleteStatement;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Utility\PersisterHelper;
use Throwable;
@@ -57,8 +59,8 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
* Internal note: Any SQL construction and preparation takes place in the constructor for
* best performance. With a query cache the executor will be cached.
*
* @param \Doctrine\ORM\Query\AST\Node $AST The root AST node of the DQL query.
* @param \Doctrine\ORM\Query\SqlWalker $sqlWalker The walker used for SQL generation from the AST.
* @param DeleteStatement $AST The root AST node of the DQL query.
* @param SqlWalker $sqlWalker The walker used for SQL generation from the AST.
*/
public function __construct(AST\Node $AST, $sqlWalker)
{
@@ -116,6 +118,8 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
/**
* {@inheritDoc}
*
* @return int
*/
public function execute(Connection $conn, array $params, array $types)
{

View File

@@ -21,8 +21,10 @@ namespace Doctrine\ORM\Query\Exec;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Query\AST\UpdateStatement;
use Doctrine\ORM\Query\ParameterTypeInferer;
use Doctrine\ORM\Query\AST;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Utility\PersisterHelper;
use Throwable;
@@ -66,8 +68,8 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
* Internal note: Any SQL construction and preparation takes place in the constructor for
* best performance. With a query cache the executor will be cached.
*
* @param \Doctrine\ORM\Query\AST\Node $AST The root AST node of the DQL query.
* @param \Doctrine\ORM\Query\SqlWalker $sqlWalker The walker used for SQL generation from the AST.
* @param UpdateStatement $AST The root AST node of the DQL query.
* @param SqlWalker $sqlWalker The walker used for SQL generation from the AST.
*/
public function __construct(AST\Node $AST, $sqlWalker)
{
@@ -161,6 +163,8 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
/**
* {@inheritDoc}
*
* @return int
*/
public function execute(Connection $conn, array $params, array $types)
{

View File

@@ -49,6 +49,8 @@ class SingleTableDeleteUpdateExecutor extends AbstractSqlExecutor
/**
* {@inheritDoc}
*
* @return int
*/
public function execute(Connection $conn, array $params, array $types)
{

View File

@@ -41,8 +41,9 @@ class Expr
* // (u.type = ?1) AND (u.role = ?2)
* $expr->andX($expr->eq('u.type', ':1'), $expr->eq('u.role', ':2'));
*
* @param Expr\Comparison|Expr\Func|Expr\Orx|string $x Optional clause. Defaults to null, but requires at least one
* defined when converting to string.
* @param Expr\Comparison|Expr\Func|Expr\Andx|Expr\Orx|string $x Optional clause. Defaults to null,
* but requires at least one defined
* when converting to string.
*
* @return Expr\Andx
*/
@@ -60,8 +61,9 @@ class Expr
* // (u.type = ?1) OR (u.role = ?2)
* $q->where($q->expr()->orX('u.type = ?1', 'u.role = ?2'));
*
* @param mixed $x Optional clause. Defaults to null, but requires
* at least one defined when converting to string.
* @param Expr\Comparison|Expr\Func|Expr\Andx|Expr\Orx|string $x Optional clause. Defaults to null,
* but requires at least one defined
* when converting to string.
*
* @return Expr\Orx
*/
@@ -627,7 +629,7 @@ class Expr
* @param integer|string $x Starting range value to be used in BETWEEN() function.
* @param integer|string $y End point value to be used in BETWEEN() function.
*
* @return Expr\Func A BETWEEN expression.
* @return string A BETWEEN expression.
*/
public function between($val, $x, $y)
{

View File

@@ -66,7 +66,7 @@ abstract class Base
/**
* @param array $args
*
* @return Base
* @return static
*/
public function addMultiple($args = [])
{
@@ -80,7 +80,7 @@ abstract class Base
/**
* @param mixed $arg
*
* @return Base
* @return static
*
* @throws \InvalidArgumentException
*/

View File

@@ -49,7 +49,7 @@ class Composite extends Base
}
/**
* @param string $part
* @param string|object $part
*
* @return string
*/

View File

@@ -67,9 +67,9 @@ abstract class SQLFilter
* the type conversion of this type. This is usually not needed for
* strings and numeric types.
*
* @return SQLFilter The current SQL filter.
* @return self The current SQL filter.
*/
final public function setParameter($name, $value, $type = null)
final public function setParameter($name, $value, $type = null) : self
{
if (null === $type) {
$type = ParameterTypeInferer::inferType($value);

View File

@@ -30,6 +30,18 @@ use function trim;
*/
class Parameter
{
/**
* Returns the internal representation of a parameter name.
*
* @param string|int $name The parameter name or position.
*
* @return string The normalized parameter name.
*/
public static function normalizeName($name)
{
return trim((string) $name, ':');
}
/**
* The parameter name.
*
@@ -67,7 +79,7 @@ class Parameter
*/
public function __construct($name, $value, $type = null)
{
$this->name = trim($name, ':');
$this->name = self::normalizeName($name);
$this->typeSpecified = $type !== null;
$this->setValue($value, $type);

View File

@@ -21,7 +21,15 @@ namespace Doctrine\ORM\Query;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\AST\DeleteStatement;
use Doctrine\ORM\Query\AST\Functions;
use Doctrine\ORM\Query\AST\IdentificationVariableDeclaration;
use Doctrine\ORM\Query\AST\PathExpression;
use Doctrine\ORM\Query\AST\SelectStatement;
use Doctrine\ORM\Query\AST\Subselect;
use Doctrine\ORM\Query\AST\SubselectIdentificationVariableDeclaration;
use Doctrine\ORM\Query\AST\UpdateStatement;
use function assert;
use function in_array;
use function strpos;
@@ -43,7 +51,7 @@ class Parser
*
* @var array
*
* @psalm-var class-string<Functions\FunctionNode>
* @psalm-var array<string, class-string<Functions\FunctionNode>>
*/
private static $_STRING_FUNCTIONS = [
'concat' => Functions\ConcatFunction::class,
@@ -59,7 +67,7 @@ class Parser
*
* @var array
*
* @psalm-var class-string<Functions\FunctionNode>
* @psalm-var array<string, class-string<Functions\FunctionNode>>
*/
private static $_NUMERIC_FUNCTIONS = [
'length' => Functions\LengthFunction::class,
@@ -85,7 +93,7 @@ class Parser
*
* @var array
*
* @psalm-var class-string<Functions\FunctionNode>
* @psalm-var array<string, class-string<Functions\FunctionNode>>
*/
private static $_DATETIME_FUNCTIONS = [
'current_date' => Functions\CurrentDateFunction::class,
@@ -257,9 +265,7 @@ class Parser
/**
* Parses and builds AST for the given Query.
*
* @return \Doctrine\ORM\Query\AST\SelectStatement |
* \Doctrine\ORM\Query\AST\UpdateStatement |
* \Doctrine\ORM\Query\AST\DeleteStatement
* @return SelectStatement|UpdateStatement|DeleteStatement
*/
public function getAST()
{
@@ -424,6 +430,8 @@ class Parser
return;
}
assert($AST instanceof AST\SelectStatement);
foreach ($this->queryComponents as $dqlAlias => $qComp) {
if ( ! isset($this->identVariableExpressions[$dqlAlias])) {
continue;
@@ -622,7 +630,7 @@ class Parser
/**
* Validates that the given <tt>NewObjectExpression</tt>.
*
* @param \Doctrine\ORM\Query\AST\SelectClause $AST
* @param SelectStatement $AST
*
* @return void
*/
@@ -839,9 +847,7 @@ class Parser
/**
* QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
*
* @return \Doctrine\ORM\Query\AST\SelectStatement |
* \Doctrine\ORM\Query\AST\UpdateStatement |
* \Doctrine\ORM\Query\AST\DeleteStatement
* @return SelectStatement|UpdateStatement|DeleteStatement
*/
public function QueryLanguage()
{
@@ -878,7 +884,7 @@ class Parser
/**
* SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
*
* @return \Doctrine\ORM\Query\AST\SelectStatement
* @return SelectStatement
*/
public function SelectStatement()
{
@@ -895,7 +901,7 @@ class Parser
/**
* UpdateStatement ::= UpdateClause [WhereClause]
*
* @return \Doctrine\ORM\Query\AST\UpdateStatement
* @return UpdateStatement
*/
public function UpdateStatement()
{
@@ -909,7 +915,7 @@ class Parser
/**
* DeleteStatement ::= DeleteClause [WhereClause]
*
* @return \Doctrine\ORM\Query\AST\DeleteStatement
* @return DeleteStatement
*/
public function DeleteStatement()
{
@@ -1078,7 +1084,7 @@ class Parser
*
* @param integer $expectedTypes
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function PathExpression($expectedTypes)
{
@@ -1114,7 +1120,7 @@ class Parser
/**
* AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function AssociationPathExpression()
{
@@ -1127,7 +1133,7 @@ class Parser
/**
* SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function SingleValuedPathExpression()
{
@@ -1140,7 +1146,7 @@ class Parser
/**
* StateFieldPathExpression ::= IdentificationVariable "." StateField
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function StateFieldPathExpression()
{
@@ -1150,7 +1156,7 @@ class Parser
/**
* SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function SingleValuedAssociationPathExpression()
{
@@ -1160,7 +1166,7 @@ class Parser
/**
* CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function CollectionValuedPathExpression()
{
@@ -1425,7 +1431,7 @@ class Parser
/**
* Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
*
* @return \Doctrine\ORM\Query\AST\Subselect
* @return Subselect
*/
public function Subselect()
{
@@ -1464,7 +1470,7 @@ class Parser
/**
* GroupByItem ::= IdentificationVariable | ResultVariable | SingleValuedPathExpression
*
* @return string | \Doctrine\ORM\Query\AST\PathExpression
* @return string|PathExpression
*/
public function GroupByItem()
{
@@ -1507,10 +1513,6 @@ class Parser
$glimpse = $this->lexer->glimpse();
switch (true) {
case ($this->isFunction()):
$expr = $this->FunctionDeclaration();
break;
case ($this->isMathOperator($peek)):
$expr = $this->SimpleArithmeticExpression();
break;
@@ -1523,6 +1525,10 @@ class Parser
$expr = $this->ScalarExpression();
break;
case $this->isFunction():
$expr = $this->FunctionDeclaration();
break;
default:
$expr = $this->ResultVariable();
break;
@@ -1561,7 +1567,7 @@ class Parser
*
* SimpleArithmeticExpression covers all *Primary grammar rules and also SimpleEntityExpression
*
* @return AST\ArithmeticExpression
* @return AST\ArithmeticExpression|AST\InputParameter|null
*/
public function NewValue()
{
@@ -1583,7 +1589,7 @@ class Parser
/**
* IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {Join}*
*
* @return \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
* @return IdentificationVariableDeclaration
*/
public function IdentificationVariableDeclaration()
{
@@ -1622,8 +1628,7 @@ class Parser
* accessible is "FROM", prohibiting an easy implementation without larger
* changes.}
*
* @return \Doctrine\ORM\Query\AST\SubselectIdentificationVariableDeclaration |
* \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
* @return SubselectIdentificationVariableDeclaration|IdentificationVariableDeclaration
*/
public function SubselectIdentificationVariableDeclaration()
{
@@ -1766,7 +1771,7 @@ class Parser
/**
* JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy]
*
* @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression
* @return AST\JoinAssociationDeclaration
*/
public function JoinAssociationDeclaration()
{
@@ -2392,7 +2397,7 @@ class Parser
/**
* ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}*
*
* @return \Doctrine\ORM\Query\AST\ConditionalExpression
* @return AST\ConditionalExpression|AST\ConditionalFactor|AST\ConditionalPrimary|AST\ConditionalTerm
*/
public function ConditionalExpression()
{
@@ -2417,7 +2422,7 @@ class Parser
/**
* ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}*
*
* @return \Doctrine\ORM\Query\AST\ConditionalTerm
* @return AST\ConditionalFactor|AST\ConditionalPrimary|AST\ConditionalTerm
*/
public function ConditionalTerm()
{
@@ -2442,7 +2447,7 @@ class Parser
/**
* ConditionalFactor ::= ["NOT"] ConditionalPrimary
*
* @return \Doctrine\ORM\Query\AST\ConditionalFactor
* @return AST\ConditionalFactor|AST\ConditionalPrimary
*/
public function ConditionalFactor()
{
@@ -2689,7 +2694,7 @@ class Parser
/**
* InParameter ::= Literal | InputParameter
*
* @return string | \Doctrine\ORM\Query\AST\InputParameter
* @return AST\InputParameter|AST\Literal
*/
public function InParameter()
{
@@ -2873,8 +2878,7 @@ class Parser
/**
* StringExpression ::= StringPrimary | ResultVariable | "(" Subselect ")"
*
* @return \Doctrine\ORM\Query\AST\Subselect |
* string
* @return Subselect|string
*/
public function StringExpression()
{
@@ -2947,8 +2951,7 @@ class Parser
/**
* EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
*
* @return \Doctrine\ORM\Query\AST\PathExpression |
* \Doctrine\ORM\Query\AST\SimpleEntityExpression
* @return AST\InputParameter|PathExpression
*/
public function EntityExpression()
{
@@ -2964,7 +2967,7 @@ class Parser
/**
* SimpleEntityExpression ::= IdentificationVariable | InputParameter
*
* @return string | \Doctrine\ORM\Query\AST\InputParameter
* @return AST\InputParameter|AST\PathExpression
*/
public function SimpleEntityExpression()
{

View File

@@ -65,8 +65,7 @@ class ParserResult
/**
* Gets the ResultSetMapping for the parsed query.
*
* @return ResultSetMapping|null The result set mapping of the parsed query or NULL
* if the query is not a SELECT query.
* @return ResultSetMapping The result set mapping of the parsed query
*/
public function getResultSetMapping()
{

View File

@@ -184,7 +184,7 @@ class ResultSetMapping
* @param string|null $resultAlias The result alias with which the entity result should be
* placed in the result structure.
*
* @return ResultSetMapping This ResultSetMapping instance.
* @return static This ResultSetMapping instance.
*
* @todo Rename: addRootEntity
*/
@@ -209,7 +209,7 @@ class ResultSetMapping
* column should be used for.
* @param string $discrColumn The name of the discriminator column in the SQL result set.
*
* @return ResultSetMapping This ResultSetMapping instance.
* @return static This ResultSetMapping instance.
*
* @todo Rename: addDiscriminatorColumn
*/
@@ -227,7 +227,7 @@ class ResultSetMapping
* @param string $alias The alias of an entity result or joined entity result.
* @param string $fieldName The name of the field to use for indexing.
*
* @return ResultSetMapping This ResultSetMapping instance.
* @return static This ResultSetMapping instance.
*/
public function addIndexBy($alias, $fieldName)
{
@@ -262,7 +262,7 @@ class ResultSetMapping
*
* @param string $resultColumnName
*
* @return ResultSetMapping This ResultSetMapping instance.
* @return static This ResultSetMapping instance.
*/
public function addIndexByScalar($resultColumnName)
{
@@ -277,7 +277,7 @@ class ResultSetMapping
* @param string $alias
* @param string $resultColumnName
*
* @return ResultSetMapping This ResultSetMapping instance.
* @return static This ResultSetMapping instance.
*/
public function addIndexByColumn($alias, $resultColumnName)
{
@@ -328,7 +328,7 @@ class ResultSetMapping
* If not specified, the field is assumed to belong to the class
* designated by $alias.
*
* @return ResultSetMapping This ResultSetMapping instance.
* @return static This ResultSetMapping instance.
*
* @todo Rename: addField
*/
@@ -357,7 +357,7 @@ class ResultSetMapping
* @param string $relation The association field that connects the parent entity result
* with the joined entity result.
*
* @return ResultSetMapping This ResultSetMapping instance.
* @return static This ResultSetMapping instance.
*
* @todo Rename: addJoinedEntity
*/
@@ -377,7 +377,7 @@ class ResultSetMapping
* @param string $alias The result alias with which the scalar result should be placed in the result structure.
* @param string $type The column type
*
* @return ResultSetMapping This ResultSetMapping instance.
* @return static This ResultSetMapping instance.
*
* @todo Rename: addScalar
*/
@@ -564,7 +564,7 @@ class ResultSetMapping
* @param bool $isIdentifierColumn
* @param string $type The column type
*
* @return ResultSetMapping This ResultSetMapping instance.
* @return static This ResultSetMapping instance.
*
* @todo Make all methods of this class require all parameters and not infer anything
*/

View File

@@ -23,6 +23,7 @@ use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\ORM\Utility\PersisterHelper;
use function explode;
/**
* A ResultSetMappingBuilder uses the EntityManager to automatically populate entity fields.
@@ -223,7 +224,9 @@ class ResultSetMappingBuilder extends ResultSetMapping
* @param int $mode
* @param array $customRenameColumns
*
* @return array
* @return string[]
*
* @psalm-return array<array-key, string>
*/
private function getColumnAliasMap($className, $mode, array $customRenameColumns)
{
@@ -273,7 +276,7 @@ class ResultSetMappingBuilder extends ResultSetMapping
* @param ClassMetadataInfo $class
* @param string $resultClassName
*
* @return ResultSetMappingBuilder
* @return self
*/
public function addNamedNativeQueryResultClassMapping(ClassMetadataInfo $class, $resultClassName)
{
@@ -318,7 +321,7 @@ class ResultSetMappingBuilder extends ResultSetMapping
* @param ClassMetadataInfo $class
* @param string $resultSetMappingName
*
* @return ResultSetMappingBuilder
* @return self
*/
public function addNamedNativeQueryResultSetMapping(ClassMetadataInfo $class, $resultSetMappingName)
{
@@ -370,7 +373,7 @@ class ResultSetMappingBuilder extends ResultSetMapping
* @param array $entityMapping
* @param string $alias
*
* @return ResultSetMappingBuilder
* @return self
*
* @throws MappingException
* @throws \InvalidArgumentException
@@ -391,7 +394,7 @@ class ResultSetMappingBuilder extends ResultSetMapping
$relation = null;
if (strpos($fieldName, '.') !== false) {
list($relation, $fieldName) = explode('.', $fieldName);
[$relation, $fieldName] = explode('.', $fieldName);
}
if (isset($classMetadata->associationMappings[$relation])) {

View File

@@ -108,7 +108,7 @@ class SqlWalker implements TreeWalker
private $conn;
/**
* @var \Doctrine\ORM\AbstractQuery
* @var Query
*/
private $query;
@@ -143,7 +143,7 @@ class SqlWalker implements TreeWalker
*
* @var array
*
* @psalm-var array<string, array{metadata: ClassMetadata}>
* @psalm-var array<string, array{metadata: ClassMetadata, token: array, relation: mixed[], parent: string}>
*/
private $queryComponents;
@@ -366,8 +366,12 @@ class SqlWalker implements TreeWalker
$sqlParts = [];
foreach ($this->quoteStrategy->getIdentifierColumnNames($class, $this->platform) as $columnName) {
$sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// Use the correct name for the id column as named in the parent class.
$identifierColumn = $this->quoteStrategy->getIdentifierColumnNames($class, $this->platform);
$parentIdentifierColumn = $this->quoteStrategy->getIdentifierColumnNames($parentClass, $this->platform);
foreach ($identifierColumn as $index => $idColumn) {
$sqlParts[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $parentIdentifierColumn[$index];
}
// Add filters on the root class
@@ -661,11 +665,21 @@ class SqlWalker implements TreeWalker
$dqlAlias = $pathExpr->identificationVariable;
$class = $this->queryComponents[$dqlAlias]['metadata'];
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// Use the correct name for the id column as named in the inherited class.
$mapping = $class->fieldMappings[$fieldName];
if (isset($mapping['inherited'])) {
$inheritedClass = $this->em->getClassMetadata($mapping['inherited']);
$quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $inheritedClass, $this->platform);
} else {
$quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform);
}
if ($this->useSqlTableAliases) {
$sql .= $this->walkIdentificationVariable($dqlAlias, $fieldName) . '.';
}
$sql .= $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform);
$sql .= $quotedColumnName;
break;
case AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION:
@@ -1405,13 +1419,19 @@ class SqlWalker implements TreeWalker
continue;
}
$tableName = (isset($mapping['inherited']))
? $this->em->getClassMetadata($mapping['inherited'])->getTableName()
: $class->getTableName();
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// Use the correct name for the id column as named in the inherited class.
if (isset($mapping['inherited'])) {
$inheritedClass = $this->em->getClassMetadata($mapping['inherited']);
$tableName = $inheritedClass->getTableName();
$quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $inheritedClass, $this->platform);
} else {
$tableName = $class->getTableName();
$quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform);
}
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
$columnAlias = $this->getSQLColumnAlias($mapping['columnName']);
$quotedColumnName = $this->quoteStrategy->getColumnName($fieldName, $class, $this->platform);
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
$columnAlias = $this->getSQLColumnAlias($mapping['columnName']);
$col = $sqlTableAlias . '.' . $quotedColumnName;
@@ -2080,7 +2100,9 @@ class SqlWalker implements TreeWalker
}
/**
* {@inheritdoc}
* @param mixed $inParam
*
* @return string
*/
public function walkInParameter($inParam)
{

View File

@@ -111,6 +111,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSelectStatement(AST\SelectStatement $AST)
{
@@ -118,6 +120,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSelectClause($selectClause)
{
@@ -125,6 +129,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkFromClause($fromClause)
{
@@ -132,6 +138,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkFunction($function)
{
@@ -139,6 +147,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkOrderByClause($orderByClause)
{
@@ -146,6 +156,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkOrderByItem($orderByItem)
{
@@ -153,6 +165,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkHavingClause($havingClause)
{
@@ -160,6 +174,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkJoin($join)
{
@@ -167,6 +183,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSelectExpression($selectExpression)
{
@@ -174,6 +192,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkQuantifiedExpression($qExpr)
{
@@ -181,6 +201,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSubselect($subselect)
{
@@ -188,6 +210,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSubselectFromClause($subselectFromClause)
{
@@ -195,6 +219,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSimpleSelectClause($simpleSelectClause)
{
@@ -202,6 +228,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSimpleSelectExpression($simpleSelectExpression)
{
@@ -209,6 +237,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkAggregateExpression($aggExpression)
{
@@ -216,6 +246,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkGroupByClause($groupByClause)
{
@@ -223,6 +255,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkGroupByItem($groupByItem)
{
@@ -230,6 +264,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkUpdateStatement(AST\UpdateStatement $AST)
{
@@ -237,6 +273,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkDeleteStatement(AST\DeleteStatement $AST)
{
@@ -244,6 +282,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkDeleteClause(AST\DeleteClause $deleteClause)
{
@@ -251,6 +291,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkUpdateClause($updateClause)
{
@@ -258,6 +300,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkUpdateItem($updateItem)
{
@@ -265,6 +309,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkWhereClause($whereClause)
{
@@ -272,6 +318,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkConditionalExpression($condExpr)
{
@@ -279,6 +327,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkConditionalTerm($condTerm)
{
@@ -286,6 +336,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkConditionalFactor($factor)
{
@@ -293,6 +345,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkConditionalPrimary($primary)
{
@@ -300,6 +354,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkExistsExpression($existsExpr)
{
@@ -307,6 +363,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkCollectionMemberExpression($collMemberExpr)
{
@@ -314,6 +372,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkEmptyCollectionComparisonExpression($emptyCollCompExpr)
{
@@ -321,6 +381,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkNullComparisonExpression($nullCompExpr)
{
@@ -328,6 +390,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkInExpression($inExpr)
{
@@ -335,6 +399,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkInstanceOfExpression($instanceOfExpr)
{
@@ -342,6 +408,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkLiteral($literal)
{
@@ -349,6 +417,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkBetweenExpression($betweenExpr)
{
@@ -356,6 +426,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkLikeExpression($likeExpr)
{
@@ -363,6 +435,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkStateFieldPathExpression($stateFieldPathExpression)
{
@@ -370,6 +444,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkComparisonExpression($compExpr)
{
@@ -377,6 +453,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkInputParameter($inputParam)
{
@@ -384,6 +462,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkArithmeticExpression($arithmeticExpr)
{
@@ -391,6 +471,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkArithmeticTerm($term)
{
@@ -398,6 +480,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkStringPrimary($stringPrimary)
{
@@ -405,6 +489,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkArithmeticFactor($factor)
{
@@ -412,6 +498,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSimpleArithmeticExpression($simpleArithmeticExpr)
{
@@ -419,6 +507,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkPathExpression($pathExpr)
{
@@ -426,6 +516,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkResultVariable($resultVariable)
{
@@ -433,6 +525,8 @@ abstract class TreeWalkerAdapter implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function getExecutor($AST)
{

View File

@@ -33,6 +33,7 @@ class TreeWalkerChain implements TreeWalker
* The tree walkers.
*
* @var TreeWalker[]
* @psalm-var TreeWalkerChainIterator
*/
private $_walkers;
@@ -69,6 +70,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function setQueryComponent($dqlAlias, array $queryComponent)
{
@@ -106,6 +109,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSelectStatement(AST\SelectStatement $AST)
{
@@ -118,6 +123,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSelectClause($selectClause)
{
@@ -128,6 +135,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkFromClause($fromClause)
{
@@ -138,6 +147,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkFunction($function)
{
@@ -148,6 +159,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkOrderByClause($orderByClause)
{
@@ -158,6 +171,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkOrderByItem($orderByItem)
{
@@ -168,6 +183,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkHavingClause($havingClause)
{
@@ -178,6 +195,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkJoin($join)
{
@@ -188,6 +207,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSelectExpression($selectExpression)
{
@@ -198,6 +219,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkQuantifiedExpression($qExpr)
{
@@ -208,6 +231,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSubselect($subselect)
{
@@ -218,6 +243,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSubselectFromClause($subselectFromClause)
{
@@ -228,6 +255,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSimpleSelectClause($simpleSelectClause)
{
@@ -238,6 +267,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSimpleSelectExpression($simpleSelectExpression)
{
@@ -248,6 +279,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkAggregateExpression($aggExpression)
{
@@ -258,6 +291,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkGroupByClause($groupByClause)
{
@@ -268,6 +303,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkGroupByItem($groupByItem)
{
@@ -278,6 +315,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkUpdateStatement(AST\UpdateStatement $AST)
{
@@ -288,6 +327,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkDeleteStatement(AST\DeleteStatement $AST)
{
@@ -298,6 +339,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkDeleteClause(AST\DeleteClause $deleteClause)
{
@@ -308,6 +351,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkUpdateClause($updateClause)
{
@@ -318,6 +363,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkUpdateItem($updateItem)
{
@@ -328,6 +375,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkWhereClause($whereClause)
{
@@ -338,6 +387,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkConditionalExpression($condExpr)
{
@@ -348,6 +399,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkConditionalTerm($condTerm)
{
@@ -358,6 +411,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkConditionalFactor($factor)
{
@@ -368,6 +423,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkConditionalPrimary($condPrimary)
{
@@ -378,6 +435,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkExistsExpression($existsExpr)
{
@@ -388,6 +447,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkCollectionMemberExpression($collMemberExpr)
{
@@ -398,6 +459,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkEmptyCollectionComparisonExpression($emptyCollCompExpr)
{
@@ -408,6 +471,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkNullComparisonExpression($nullCompExpr)
{
@@ -418,6 +483,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkInExpression($inExpr)
{
@@ -428,6 +495,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkInstanceOfExpression($instanceOfExpr)
{
@@ -438,6 +507,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkLiteral($literal)
{
@@ -448,6 +519,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkBetweenExpression($betweenExpr)
{
@@ -458,6 +531,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkLikeExpression($likeExpr)
{
@@ -468,6 +543,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkStateFieldPathExpression($stateFieldPathExpression)
{
@@ -478,6 +555,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkComparisonExpression($compExpr)
{
@@ -488,6 +567,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkInputParameter($inputParam)
{
@@ -498,6 +579,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkArithmeticExpression($arithmeticExpr)
{
@@ -508,6 +591,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkArithmeticTerm($term)
{
@@ -518,6 +603,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkStringPrimary($stringPrimary)
{
@@ -528,6 +615,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkArithmeticFactor($factor)
{
@@ -538,6 +627,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkSimpleArithmeticExpression($simpleArithmeticExpr)
{
@@ -548,6 +639,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkPathExpression($pathExpr)
{
@@ -558,6 +651,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function walkResultVariable($resultVariable)
{
@@ -568,6 +663,8 @@ class TreeWalkerChain implements TreeWalker
/**
* {@inheritdoc}
*
* @return void
*/
public function getExecutor($AST)
{

View File

@@ -19,8 +19,11 @@
namespace Doctrine\ORM\Query;
use Doctrine\ORM\AbstractQuery;
/**
*
* @template-implements \Iterator<TreeWalker>
* @template-implements \ArrayAccess<int, TreeWalker>
*/
class TreeWalkerChainIterator implements \Iterator, \ArrayAccess
{
@@ -33,14 +36,18 @@ class TreeWalkerChainIterator implements \Iterator, \ArrayAccess
*/
private $treeWalkerChain;
/**
* @var
* @var AbstractQuery
*/
private $query;
/**
* @var
* @var ParserResult
*/
private $parserResult;
/**
* @param AbstractQuery $query
* @param ParserResult $parserResult
*/
public function __construct(TreeWalkerChain $treeWalkerChain, $query, $parserResult)
{
$this->treeWalkerChain = $treeWalkerChain;
@@ -49,7 +56,9 @@ class TreeWalkerChainIterator implements \Iterator, \ArrayAccess
}
/**
* {@inheritdoc}
* @return string|false
*
* @psalm-return class-string<TreeWalker>|false
*/
public function rewind()
{
@@ -57,7 +66,7 @@ class TreeWalkerChainIterator implements \Iterator, \ArrayAccess
}
/**
* {@inheritdoc}
* @return TreeWalker|null
*/
public function current()
{
@@ -65,7 +74,7 @@ class TreeWalkerChainIterator implements \Iterator, \ArrayAccess
}
/**
* {@inheritdoc}
* @return int
*/
public function key()
{
@@ -73,7 +82,7 @@ class TreeWalkerChainIterator implements \Iterator, \ArrayAccess
}
/**
* {@inheritdoc}
* @return TreeWalker|null
*/
public function next()
{
@@ -99,7 +108,7 @@ class TreeWalkerChainIterator implements \Iterator, \ArrayAccess
}
/**
* {@inheritdoc}
* @return TreeWalker|null
*/
public function offsetGet($offset)
{

View File

@@ -440,7 +440,9 @@ class QueryBuilder
* $qb->getRootAliases(); // array('u')
* </code>
*
* @return array
* @return mixed[]
*
* @psalm-return list<mixed>
*/
public function getRootAliases()
{
@@ -473,7 +475,10 @@ class QueryBuilder
*
* $qb->getAllAliases(); // array('u','a')
* </code>
* @return array
*
* @return mixed[]
*
* @psalm-return list<mixed>
*/
public function getAllAliases()
{
@@ -492,7 +497,9 @@ class QueryBuilder
* $qb->getRootEntities(); // array('User')
* </code>
*
* @return array
* @return mixed[]
*
* @psalm-return list<mixed>
*/
public function getRootEntities()
{
@@ -567,6 +574,7 @@ class QueryBuilder
{
// BC compatibility with 2.3-
if (is_array($parameters)) {
/** @psalm-var ArrayCollection<int, Query\Parameter> $parameterCollection */
$parameterCollection = new ArrayCollection();
foreach ($parameters as $key => $value) {
@@ -602,11 +610,13 @@ class QueryBuilder
*/
public function getParameter($key)
{
$key = Query\Parameter::normalizeName($key);
$filteredParameters = $this->parameters->filter(
function (Query\Parameter $parameter) use ($key) : bool {
$parameterName = $parameter->getName();
return $key === $parameterName || (string) $key === (string) $parameterName;
return $key === $parameterName;
}
);

View File

@@ -61,7 +61,6 @@ final class DefaultRepositoryFactory implements RepositoryFactory
*/
private function createRepository(EntityManagerInterface $entityManager, $entityName)
{
/* @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */
$metadata = $entityManager->getClassMetadata($entityName);
$repositoryClassName = $metadata->customRepositoryClassName
?: $entityManager->getConfiguration()->getDefaultRepositoryClassName();

View File

@@ -20,6 +20,7 @@
namespace Doctrine\ORM\Tools;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Mapping\ClassMetadata;
/**
* Mechanism to programmatically attach entity listeners.
@@ -63,7 +64,6 @@ class AttachEntityListenersListener
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $event)
{
/** @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */
$metadata = $event->getClassMetadata();
if ( ! isset($this->entityListeners[$metadata->name])) {

View File

@@ -22,6 +22,7 @@ namespace Doctrine\ORM\Tools\Console\Command;
use Doctrine\ORM\Tools\ConvertDoctrine1Schema;
use Doctrine\ORM\Tools\EntityGenerator;
use Doctrine\ORM\Tools\Export\ClassMetadataExporter;
use Doctrine\ORM\Tools\Export\Driver\AnnotationExporter;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -130,7 +131,7 @@ class ConvertDoctrine1SchemaCommand extends Command
$toType = $input->getArgument('to-type');
$extend = $input->getOption('extend');
$numSpaces = $input->getOption('num-spaces');
$numSpaces = (int) $input->getOption('num-spaces');
$this->convertDoctrine1Schema($fromPaths, $destPath, $toType, $numSpaces, $extend, $output);
@@ -180,7 +181,7 @@ class ConvertDoctrine1SchemaCommand extends Command
$cme = $this->getMetadataExporter();
$exporter = $cme->getExporter($toType, $destPath);
if (strtolower($toType) === 'annotation') {
if ($exporter instanceof AnnotationExporter) {
$entityGenerator = $this->getEntityGenerator();
$exporter->setEntityGenerator($entityGenerator);

View File

@@ -24,6 +24,7 @@ use Doctrine\ORM\Tools\Console\MetadataFilter;
use Doctrine\ORM\Tools\DisconnectedClassMetadataFactory;
use Doctrine\ORM\Tools\EntityGenerator;
use Doctrine\ORM\Tools\Export\ClassMetadataExporter;
use Doctrine\ORM\Tools\Export\Driver\AnnotationExporter;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -136,11 +137,11 @@ EOT
$exporter = $this->getExporter($toType, $destPath);
$exporter->setOverwriteExistingFiles($input->getOption('force'));
if ($toType == 'annotation') {
if ($exporter instanceof AnnotationExporter) {
$entityGenerator = new EntityGenerator();
$exporter->setEntityGenerator($entityGenerator);
$entityGenerator->setNumSpaces($input->getOption('num-spaces'));
$entityGenerator->setNumSpaces((int) $input->getOption('num-spaces'));
if (($extend = $input->getOption('extend')) !== null) {
$entityGenerator->setClassToExtend($extend);

View File

@@ -124,7 +124,7 @@ EOT
$entityGenerator->setGenerateStubMethods($input->getOption('generate-methods'));
$entityGenerator->setRegenerateEntityIfExists($input->getOption('regenerate-entities'));
$entityGenerator->setUpdateEntityIfExists($input->getOption('update-entities'));
$entityGenerator->setNumSpaces($input->getOption('num-spaces'));
$entityGenerator->setNumSpaces((int) $input->getOption('num-spaces'));
$entityGenerator->setBackupExisting(!$input->getOption('no-backup'));
if (($extend = $input->getOption('extend')) !== null) {

View File

@@ -135,7 +135,7 @@ EOT
*
* @return string[]
*/
private function getMappedEntities(EntityManagerInterface $entityManager)
private function getMappedEntities(EntityManagerInterface $entityManager) : array
{
$entityClassNames = $entityManager->getConfiguration()
->getMetadataDriverImpl()
@@ -225,7 +225,7 @@ EOT
}
if (is_scalar($value)) {
return $value;
return (string) $value;
}
throw new \InvalidArgumentException(sprintf('Do not know how to format value "%s"', print_r($value, true)));
@@ -237,9 +237,11 @@ EOT
* @param string $label Label for the value
* @param mixed $value A Value to show
*
* @return array
* @return string[]
*
* @psalm-return array{0: string, 1: string}
*/
private function formatField($label, $value)
private function formatField($label, $value) : array
{
if (null === $value) {
$value = '<comment>None</comment>';
@@ -253,9 +255,11 @@ EOT
*
* @param array $propertyMappings
*
* @return array
* @return string[][]
*
* @psalm-return list<array{0: string, 1: string}>
*/
private function formatMappings(array $propertyMappings)
private function formatMappings(array $propertyMappings) : array
{
$output = [];
@@ -275,9 +279,11 @@ EOT
*
* @param array $entityListeners
*
* @return array
* @return string[]
*
* @psalm-return array{0: string, 1: string}
*/
private function formatEntityListeners(array $entityListeners)
private function formatEntityListeners(array $entityListeners) : array
{
return $this->formatField('Entity listeners', array_map('get_class', $entityListeners));
}

View File

@@ -109,7 +109,7 @@ class RunDqlCommand extends Command
$resultSet = $query->execute([], constant($hydrationMode));
$ui->text(Debug::dump($resultSet, $input->getOption('depth'), true, false));
$ui->text(Debug::dump($resultSet, (int) $input->getOption('depth'), true, false));
return 0;
}

View File

@@ -68,7 +68,9 @@ class ConvertDoctrine1Schema
* Gets an array of ClassMetadataInfo instances from the passed
* Doctrine 1 schema.
*
* @return array An array of ClassMetadataInfo instances
* @return ClassMetadataInfo[] An array of ClassMetadataInfo instances
*
* @psalm-return list<ClassMetadataInfo>
*/
public function getMetadata()
{
@@ -170,7 +172,7 @@ class ConvertDoctrine1Schema
* @param string|array $column
* @param ClassMetadataInfo $metadata
*
* @return array
* @return mixed[]
*
* @throws ToolsException
*/

View File

@@ -23,6 +23,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Inflector\Inflector;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use ReflectionClass;
use const E_USER_DEPRECATED;
use function str_replace;
use function trigger_error;
@@ -505,11 +506,13 @@ public function __construct(<params>)
/**
* Sets the class fields visibility for the entity (can either be private or protected).
*
* @param bool $visibility
* @param string $visibility
*
* @return void
*
* @throws \InvalidArgumentException
*
* @psalm-param self::FIELD_VISIBLE_*
*/
public function setFieldVisibility($visibility)
{
@@ -920,9 +923,11 @@ public function __construct(<params>)
/**
* @param ClassMetadataInfo $metadata
*
* @return array
* @return ReflectionClass[]
*
* @throws \ReflectionException
*
* @psalm-return array<trait-string, ReflectionClass>
*/
protected function getTraits(ClassMetadataInfo $metadata)
{
@@ -1153,7 +1158,7 @@ public function __construct(<params>)
/**
* @param ClassMetadataInfo $metadata
*
* @return string
* @return string|null
*/
protected function generateDiscriminatorMapAnnotation(ClassMetadataInfo $metadata)
{

View File

@@ -170,7 +170,7 @@ class <className> extends <repositoryName>
/**
* @param string $repositoryName
*
* @return \Doctrine\ORM\Tools\EntityRepositoryGenerator
* @return self
*/
public function setDefaultRepositoryName($repositoryName)
{

View File

@@ -189,6 +189,8 @@ abstract class AbstractExporter
* @param int $type
*
* @return string
*
* @psalm-param ClassMetadataInfo::INHERITANCE_TYPE_* $type
*/
protected function _getInheritanceTypeString($type)
{
@@ -211,6 +213,8 @@ abstract class AbstractExporter
* @param int $mode
*
* @return string
*
* @psalm-param ClassMetadataInfo::FETCH_* $mode
*/
protected function _getFetchModeString($mode)
{
@@ -230,6 +234,8 @@ abstract class AbstractExporter
* @param int $policy
*
* @return string
*
* @psalm-param ClassMetadataInfo::CHANGETRACKING_* $policy
*/
protected function _getChangeTrackingPolicyString($policy)
{
@@ -249,6 +255,8 @@ abstract class AbstractExporter
* @param int $type
*
* @return string
*
* @psalm-param ClassMetadataInfo::GENERATOR_TYPE_* $type
*/
protected function _getIdGeneratorTypeString($type)
{

View File

@@ -182,6 +182,11 @@ class PhpExporter extends AbstractExporter
return $export;
}
/**
* @return string[]
*
* @psalm-return list<string>
*/
private function processEntityListeners(ClassMetadataInfo $metadata) : array
{
$lines = [];

View File

@@ -120,10 +120,7 @@ class YamlExporter extends AbstractExporter
$array['id'] = $ids;
if ($fieldMappings) {
if ( ! isset($array['fields'])) {
$array['fields'] = [];
}
$array['fields'] = array_merge($array['fields'], $fieldMappings);
$array['fields'] = $fieldMappings;
}
foreach ($metadata->associationMappings as $name => $associationMapping) {

View File

@@ -521,7 +521,9 @@ class LimitSubqueryOutputWalker extends SqlWalker
/**
* @param SelectStatement $AST
*
* @return array
* @return array-key[]
*
* @psalm-return array<array-key, array-key>
*/
private function getSQLIdentifier(SelectStatement $AST)
{

View File

@@ -158,9 +158,7 @@ class LimitSubqueryWalker extends TreeWalkerAdapter
/**
* Retrieve either an IdentityFunction (IDENTITY(u.assoc)) or a state field (u.name).
*
* @param \Doctrine\ORM\Query\AST\PathExpression $pathExpression
*
* @return \Doctrine\ORM\Query\AST\Functions\IdentityFunction
* @return IdentityFunction|PathExpression
*/
private function createSelectExpressionItem(PathExpression $pathExpression)
{

View File

@@ -25,6 +25,7 @@ use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\QueryBuilder;
use function array_map;
use function array_sum;
/**
* The paginator can handle various complex scenarios with DQL.
@@ -122,7 +123,7 @@ class Paginator implements \Countable, \IteratorAggregate
{
if ($this->count === null) {
try {
$this->count = array_sum(array_map('current', $this->getCountQuery()->getScalarResult()));
$this->count = (int) array_sum(array_map('current', $this->getCountQuery()->getScalarResult()));
} catch (NoResultException $e) {
$this->count = 0;
}
@@ -190,7 +191,6 @@ class Paginator implements \Countable, \IteratorAggregate
*/
private function cloneQuery(Query $query)
{
/* @var $cloneQuery Query */
$cloneQuery = clone $query;
$cloneQuery->setParameters(clone $query->getParameters());
@@ -244,7 +244,6 @@ class Paginator implements \Countable, \IteratorAggregate
*/
private function getCountQuery()
{
/* @var $countQuery Query */
$countQuery = $this->cloneQuery($this->query);
if ( ! $countQuery->hasHint(CountWalker::HINT_DISTINCT)) {

View File

@@ -96,7 +96,6 @@ class ResolveTargetEntityListener implements EventSubscriber
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $args)
{
/* @var $cm \Doctrine\ORM\Mapping\ClassMetadata */
$cm = $args->getClassMetadata();
foreach ($cm->associationMappings as $mapping) {

View File

@@ -31,6 +31,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use function array_intersect_key;
/**
* The SchemaTool is a tool to create/drop/update database schemas based on
@@ -107,7 +108,7 @@ class SchemaTool
*
* @param array $classes
*
* @return array The SQL statements needed to create the schema for the classes.
* @return string[] The SQL statements needed to create the schema for the classes.
*/
public function getCreateSchemaSql(array $classes)
{
@@ -248,14 +249,20 @@ class SchemaTool
}
if ( ! empty($inheritedKeyColumns)) {
// Fix for bug GH-8229 (id column from parent class renamed in child class):
// Use the correct name for the id columns as named in the parent class.
$parentClass = $this->em->getClassMetadata($class->rootEntityName);
$parentKeyColumnNames = $parentClass->getIdentifierColumnNames();
$parentKeyColumns = array_intersect_key($parentKeyColumnNames, $inheritedKeyColumns);
// Add a FK constraint on the ID column
$table->addForeignKeyConstraint(
$this->quoteStrategy->getTableName(
$this->em->getClassMetadata($class->rootEntityName),
$parentClass,
$this->platform
),
$inheritedKeyColumns,
$inheritedKeyColumns,
$parentKeyColumns,
['onDelete' => 'CASCADE']
);
}
@@ -639,7 +646,7 @@ class SchemaTool
foreach ($joinColumns as $joinColumn) {
list($definingClass, $referencedFieldName) = $this->getDefiningClass(
[$definingClass, $referencedFieldName] = $this->getDefiningClass(
$class,
$joinColumn['referencedColumnName']
);
@@ -794,7 +801,7 @@ class SchemaTool
/**
* Gets the SQL needed to drop the database schema for the connections database.
*
* @return array
* @return string[]
*/
public function getDropDatabaseSQL()
{
@@ -812,7 +819,7 @@ class SchemaTool
*
* @param array $classes
*
* @return array
* @return string[]
*/
public function getDropSchemaSQL(array $classes)
{
@@ -825,7 +832,6 @@ class SchemaTool
foreach ($fullSchema->getTables() as $table) {
if ( ! $schema->hasTable($table->getName())) {
foreach ($table->getForeignKeys() as $foreignKey) {
/* @var $foreignKey \Doctrine\DBAL\Schema\ForeignKeyConstraint */
if ($schema->hasTable($foreignKey->getForeignTableName())) {
$visitor->acceptForeignKey($table, $foreignKey);
}
@@ -888,7 +894,7 @@ class SchemaTool
* @param boolean $saveMode If TRUE, only generates SQL for a partial update
* that does not include SQL for dropping assets which are scheduled for deletion.
*
* @return array The sequence of SQL statements.
* @return string[] The sequence of SQL statements.
*/
public function getUpdateSchemaSql(array $classes, $saveMode = false)
{

View File

@@ -81,7 +81,9 @@ class SchemaValidator
*
* @param ClassMetadataInfo $class
*
* @return array
* @return string[]
*
* @psalm-return list<string>
*/
public function validateClass(ClassMetadataInfo $class)
{

View File

@@ -47,6 +47,7 @@ use InvalidArgumentException;
use Throwable;
use UnexpectedValueException;
use function get_class;
use function spl_object_hash;
/**
* The UnitOfWork is responsible for tracking changes to objects during an
@@ -472,7 +473,7 @@ class UnitOfWork implements PropertyChangedListener
: $entity;
foreach ($entities as $object) {
$oid = \spl_object_hash($object);
$oid = spl_object_hash($object);
$this->clearEntityChangeSet($oid);
@@ -548,7 +549,7 @@ class UnitOfWork implements PropertyChangedListener
private function executeExtraUpdates()
{
foreach ($this->extraUpdates as $oid => $update) {
list ($entity, $changeset) = $update;
[$entity, $changeset] = $update;
$this->entityChangeSets[$oid] = $changeset;
$this->getEntityPersister(get_class($entity))->update($entity);
@@ -897,7 +898,7 @@ class UnitOfWork implements PropertyChangedListener
* through the object-graph where cascade-persistence
* is enabled for this object.
*/
$this->nonCascadedNewDetectedEntities[\spl_object_hash($entry)] = [$assoc, $entry];
$this->nonCascadedNewDetectedEntities[spl_object_hash($entry)] = [$assoc, $entry];
break;
}
@@ -1393,7 +1394,7 @@ class UnitOfWork implements PropertyChangedListener
$extraUpdate = [$entity, $changeset];
if (isset($this->extraUpdates[$oid])) {
list(, $changeset2) = $this->extraUpdates[$oid];
[, $changeset2] = $this->extraUpdates[$oid];
$extraUpdate = [$entity, $changeset + $changeset2];
}
@@ -3043,8 +3044,8 @@ class UnitOfWork implements PropertyChangedListener
* @param mixed $id The entity identifier to look for.
* @param string $rootClassName The name of the root class of the mapped entity hierarchy.
*
* @return object|bool Returns the entity with the specified identifier if it exists in
* this UnitOfWork, FALSE otherwise.
* @return object|false Returns the entity with the specified identifier if it exists in
* this UnitOfWork, FALSE otherwise.
*/
public function tryGetById($id, $rootClassName)
{
@@ -3214,17 +3215,17 @@ class UnitOfWork implements PropertyChangedListener
/**
* Notifies this UnitOfWork of a property change in an entity.
*
* @param object $entity The entity that owns the property.
* @param object $sender The entity that owns the property.
* @param string $propertyName The name of the property that changed.
* @param mixed $oldValue The old value of the property.
* @param mixed $newValue The new value of the property.
*
* @return void
*/
public function propertyChanged($entity, $propertyName, $oldValue, $newValue)
public function propertyChanged($sender, $propertyName, $oldValue, $newValue)
{
$oid = spl_object_hash($entity);
$class = $this->em->getClassMetadata(get_class($entity));
$oid = spl_object_hash($sender);
$class = $this->em->getClassMetadata(get_class($sender));
$isAssocField = isset($class->associationMappings[$propertyName]);
@@ -3236,7 +3237,7 @@ class UnitOfWork implements PropertyChangedListener
$this->entityChangeSets[$oid][$propertyName] = [$oldValue, $newValue];
if ( ! isset($this->scheduledForSynchronization[$class->rootEntityName][$oid])) {
$this->scheduleForDirtyCheck($entity);
$this->scheduleForDirtyCheck($sender);
}
}

View File

@@ -18,6 +18,10 @@ final class HierarchyDiscriminatorResolver
/**
* This method is needed to make INSTANCEOF work correctly with inheritance: if the class at hand has inheritance,
* it extracts all the discriminators from the child classes and returns them
*
* @return null[]
*
* @psalm-return array<array-key, null>
*/
public static function resolveDiscriminatorsForClass(
ClassMetadata $rootClassMetadata,

Some files were not shown because too many files have changed in this diff Show More