Compare commits

...

46 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
Grégoire Paris
d95e03ba66 Allow doctrine/common 3 and doctrine/persistence 2 (#8158) 2020-05-26 18:03:49 +02:00
Robert Basic
825ceb6b7a Fix inline code example (#8153)
* Fix inline code example

* Remove extra backslash
2020-05-22 22:45:24 +02:00
orklah
de2e2a1d74 Add psalm types (#7989) 2020-05-18 21:48:28 +02:00
Grégoire Paris
6780a963f7 Migrate git-phpcs to Github actions (#8146) 2020-05-16 14:01:10 +02:00
Benjamin Eberlei
4d172e2591 Revert changes to embeddable mapping in 2.7 (#8138)
* Revert "Fix inherited embeddables and nesting after AnnotationDriver change #8006 (#8036)"

This reverts commit a9b6b72017.

* Revert "Make Embeddable not transient"

This reverts commit 58677c29b4.

* Housekeeping: CS fixes
2020-05-12 20:10:26 +02:00
Grégoire Paris
21a98234d0 Static analysis with Psalm (#8116)
* Remove useless ternaries

If these expressions are truish inside the condition, they will still be
truish inside the if.

* Describe properties more accurately

These are not objects, they are strings holding class names for classes
that implement TreeWalker.

* Remove duplicate key

Comparison::IS and Comparison::EQ are the same. I chose to remove IS
because it does not seem to exist anymore on master

* Remove unwanted . before = operator

This worked, but makes no sense.

* Setup static analysis with Psalm

* Move PHPStan to Github actions
2020-05-11 23:06:46 +02:00
Grégoire Paris
8a9954e46c Address deprecations from persistence (#7953)
A backwards-compatibility layer has been added to persistence to help
consumers move to the new namespacing. It is based on class aliases,
which means the type declaration changes should not be a BC-break: types
are the same.
See https://github.com/doctrine/persistence/pull/71

This means:
- using the new namespaces
- adding autoload calls for new types to types that may be extended and
use persistence types in type declarations of non-constructor methods,
so that signature compatibility is recognized by old versions of php.
More details on this at
https://dev.to/greg0ire/how-to-deprecate-a-type-in-php-48cf
2020-05-07 08:35:39 +02:00
Grzesiek
527fff53cc removed repository class from metadata (#8125)
The annotation is required only in the next chapter of the tutorial, specifically the "Entity Repositories"
2020-05-03 21:58:20 +02:00
Maks Rafalko
70fb1ecd78 Warn users about performance issues with DateTime objects in setParameter() (#8114) 2020-04-25 22:16:17 +02:00
Jeroen van den Heuvel
73ec483e9d Convert PHP to SQL for new object expression (#8062) 2020-04-16 23:01:43 +02:00
Mathieu
8d67eec812 Fix JoinColumn documentation (#7966) 2020-03-30 21:33:13 +02:00
Vincent Langlet
a418cf6418 Remove TODO (#8078) 2020-03-30 20:06:04 +02:00
Arne
6138afdca9 [Docs] Make clear that calling remove() detaches the object (#8081)
I changed a relationship from eager to lazy loading which broker the behaviour of my application in regards to object removal. It was not clear for me that removing an object detaches it and subsequent calls like contains() in a OneToMany relationship with the object scheduled for removal will return false afterwards.
2020-03-27 19:42:39 +01:00
193 changed files with 3313 additions and 1398 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

111
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,111 @@
name: CI
on:
pull_request:
jobs:
static-analysis-phpstan:
name: "Static Analysis with PHPStan"
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout code"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: cs2pr
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
- name: "Install dependencies with composer"
run: "composer install --no-progress --no-suggest --no-interaction --prefer-dist"
- name: "Run a static analysis with phpstan/phpstan"
run: "php vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr"
static-analysis-psalm:
name: "Static Analysis with Psalm"
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout code"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
- name: "Install dependencies with composer"
run: "composer install --no-interaction --no-progress --no-suggest"
- name: "Run a static analysis with vimeo/psalm"
run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"
coding-standards:
name: "Coding Standards"
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 10
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: "cs2pr"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
- name: "Install dependencies with composer"
run: "composer install --no-interaction --no-progress --no-suggest"
- name: "Install git-phpcs"
run: "wget https://github.com/diff-sniffer/git/releases/download/0.3.2/git-phpcs.phar"
- name: "Fetch head branch"
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"

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,22 +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
- stage: Code Quality
env: DB=none STATIC_ANALYSIS
php: 7.4
install: travis_retry composer install --prefer-dist
before_script:
- echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- echo "extension=redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- travis_retry composer require --dev --prefer-dist --prefer-stable phpstan/phpstan:^0.9
script: vendor/bin/phpstan analyse -l 1 -c phpstan.neon lib
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
@@ -107,21 +97,6 @@ jobs:
script:
- ./vendor/bin/phpcs
- stage: Code Quality
if: type = pull_request
env: DB=none PULL_REQUEST_CODING_STANDARDS
php: 7.1
install: travis_retry composer install --prefer-dist
script:
- |
if [ $TRAVIS_BRANCH != "master" ]; then
git remote set-branches --add origin $TRAVIS_BRANCH;
git fetch origin $TRAVIS_BRANCH;
fi
- git merge-base origin/$TRAVIS_BRANCH $TRAVIS_PULL_REQUEST_SHA || git fetch origin +refs/pull/$TRAVIS_PULL_REQUEST/merge --unshallow
- wget https://github.com/diff-sniffer/git/releases/download/0.2.0/git-phpcs.phar
- php git-phpcs.phar origin/$TRAVIS_BRANCH...$TRAVIS_PULL_REQUEST_SHA
allow_failures:
- stage: Code Quality
env: DB=none CODING_STANDARDS

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

@@ -47,7 +47,7 @@ Whole Doctrine\ORM\Tools\Export namespace with all its members have been depreca
## Deprecated `Doctrine\ORM\Proxy\Proxy` marker interface
Proxy objects in Doctrine ORM 3.0 will no longer implement `Doctrine\ORM\Proxy\Proxy` nor
`Doctrine\Common\Persistence\Proxy`: instead, they implement
`Doctrine\Persistence\Proxy`: instead, they implement
`ProxyManager\Proxy\GhostObjectInterface`.
These related classes have been deprecated:
@@ -439,17 +439,17 @@ above you must implement these new methods.
## Metadata Drivers
Metadata drivers have been rewritten to reuse code from Doctrine\Common. Anyone who is using the
Metadata drivers have been rewritten to reuse code from `Doctrine\Persistence`. Anyone who is using the
`Doctrine\ORM\Mapping\Driver\Driver` interface should instead refer to
`Doctrine\Common\Persistence\Mapping\Driver\MappingDriver`. Same applies to
`Doctrine\Persistence\Mapping\Driver\MappingDriver`. Same applies to
`Doctrine\ORM\Mapping\Driver\AbstractFileDriver`: you should now refer to
`Doctrine\Common\Persistence\Mapping\Driver\FileDriver`.
`Doctrine\Persistence\Mapping\Driver\FileDriver`.
Also, following mapping drivers have been deprecated, please use their replacements in Doctrine\Common as listed:
* `Doctrine\ORM\Mapping\Driver\DriverChain` => `Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain`
* `Doctrine\ORM\Mapping\Driver\PHPDriver` => `Doctrine\Common\Persistence\Mapping\Driver\PHPDriver`
* `Doctrine\ORM\Mapping\Driver\StaticPHPDriver` => `Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver`
* `Doctrine\ORM\Mapping\Driver\DriverChain` => `Doctrine\Persistence\Mapping\Driver\MappingDriverChain`
* `Doctrine\ORM\Mapping\Driver\PHPDriver` => `Doctrine\Persistence\Mapping\Driver\PHPDriver`
* `Doctrine\ORM\Mapping\Driver\StaticPHPDriver` => `Doctrine\Persistence\Mapping\Driver\StaticPHPDriver`
# Upgrade to 2.2
@@ -538,7 +538,7 @@ Previously EntityManager#find(null) returned null. It now throws an exception.
## Interface for EntityRepository
The EntityRepository now has an interface Doctrine\Common\Persistence\ObjectRepository. This means that your classes that override EntityRepository and extend find(), findOneBy() or findBy() must be adjusted to follow this interface.
The EntityRepository now has an interface Doctrine\Persistence\ObjectRepository. This means that your classes that override EntityRepository and extend find(), findOneBy() or findBy() must be adjusted to follow this interface.
## AnnotationReader changes

View File

@@ -13,26 +13,33 @@
{"name": "Marco Pivetta", "email": "ocramius@gmail.com"}
],
"config": {
"platform": {
"php": "7.1.3"
},
"sort-packages": true
},
"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",
"doctrine/common": "^2.11",
"doctrine/common": "^2.11 || ^3.0",
"doctrine/dbal": "^2.9.3",
"doctrine/event-manager": "^1.1",
"doctrine/inflector": "^1.0",
"doctrine/instantiator": "^1.3",
"doctrine/persistence": "^1.2",
"ocramius/package-versions": "^1.2",
"doctrine/lexer": "^1.0",
"doctrine/persistence": "^1.3.3 || ^2.0",
"symfony/console": "^3.0|^4.0|^5.0"
},
"require-dev": {
"doctrine/coding-standard": "^5.0",
"phpstan/phpstan": "^0.12.18",
"phpunit/phpunit": "^7.5",
"symfony/yaml": "^3.4|^4.0|^5.0"
"symfony/yaml": "^3.4|^4.0|^5.0",
"vimeo/psalm": "^3.11"
},
"suggest": {
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"

1551
composer.lock generated

File diff suppressed because it is too large Load Diff

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

@@ -22,8 +22,8 @@ implement the ``NotifyPropertyChanged`` interface from the
.. code-block:: php
<?php
use Doctrine\Common\NotifyPropertyChanged;
use Doctrine\Common\PropertyChangedListener;
use Doctrine\Persistence\NotifyPropertyChanged;
use Doctrine\Persistence\PropertyChangedListener;
abstract class DomainObject implements NotifyPropertyChanged
{

View File

@@ -619,22 +619,17 @@ Examples:
This annotation is used in the context of relations in
:ref:`@ManyToOne <annref_manytoone>`, :ref:`@OneToOne <annref_onetoone>` fields
and in the Context of :ref:`@JoinTable <annref_jointable>` nested inside
a @ManyToMany. This annotation is not required. If it is not
specified the attributes *name* and *referencedColumnName* are
inferred from the table and primary key names.
Required attributes:
a @ManyToMany. If this annotation or both *name* and *referencedColumnName*
are missing they will be computed considering the field's name and the current
:doc:`naming strategy <namingstrategy>`.
Optional attributes:
- **name**: Column name that holds the foreign key identifier for
this relation. In the context of @JoinTable it specifies the column
name in the join table.
- **referencedColumnName**: Name of the primary key identifier that
is used for joining of this relation.
Optional attributes:
is used for joining of this relation. Defaults to *id*.
- **unique**: Determines whether this relation is exclusive between the
affected entities and should be enforced as such on the database
constraint level. Defaults to false.

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

@@ -71,8 +71,8 @@ follows:
.. code-block:: php
<?php
use Doctrine\Common\NotifyPropertyChanged,
Doctrine\Common\PropertyChangedListener;
use Doctrine\Persistence\NotifyPropertyChanged,
Doctrine\Persistence\PropertyChangedListener;
/**
* @Entity

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
@@ -423,7 +427,7 @@ A lifecycle event listener looks like the following:
.. code-block:: php
<?php
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\Persistence\Event\LifecycleEventArgs;
class MyEventListener
{
@@ -445,8 +449,8 @@ A lifecycle event subscriber may look like this:
<?php
use Doctrine\ORM\Events;
use Doctrine\Common\EventSubscriber;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\EventSubscriber;
use Doctrine\Persistence\Event\LifecycleEventArgs;
class MyEventSubscriber implements EventSubscriber
{
@@ -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

@@ -255,6 +255,21 @@ and for managed entities. If you want to set a type explicitly you can call
the third argument to ``setParameter()`` explicitly. It accepts either a PDO
type or a DBAL Type name for conversion.
.. note::
Even though passing DateTime instance is allowed, it impacts performance
as by default there is an attempt to load metadata for object, and if it's not found,
type is inferred from the original value.
.. code-block:: php
<?php
use Doctrine\DBAL\Types\Types;
// prevents attempt to load metadata for date time class, improving performance
$qb->setParameter('date', new \DateTimeImmutable(), Types::DATE_IMMUTABLE)
If you've got several parameters to bind to your query, you can
also use setParameters() instead of setParameter() with the
following syntax:
@@ -581,4 +596,3 @@ same query of example 6 written using
->add('from', new Expr\From('User', 'u'))
->add('where', new Expr\Comparison('u.id', '=', '?1'))
->add('orderBy', new Expr\OrderBy('u.name', 'ASC'));

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
-----------------
@@ -315,7 +321,7 @@ in multiple ways with very different performance impacts.
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine 2
will fetch this association. If its a Single association it will
pass this entity to
´EntityManager#remove()``. If the association is a collection, Doctrine will loop over all its elements and pass them to``EntityManager#remove()\`.
``EntityManager#remove()``. If the association is a collection, Doctrine will loop over all its elements and pass them to``EntityManager#remove()``.
In both cases the cascade remove semantics are applied recursively.
For large object graphs this removal strategy can be very costly.
2. Using a DQL ``DELETE`` statement allows you to delete multiple
@@ -330,6 +336,13 @@ in multiple ways with very different performance impacts.
because Doctrine will fetch and remove all associated entities
explicitly nevertheless.
.. note::
Calling ``remove`` on an entity will remove the object from the identiy
map and therefore detach it. Querying the same entity again, for example
via a lazy loaded relation, will return a new object.
Detaching entities
------------------

View File

@@ -8,9 +8,7 @@ or address are the primary use case for this feature.
.. note::
Embeddables can not contain references to entities. They can however compose
other embeddables in addition to holding properties with basic ``@Column``
mapping.
Embeddables can only contain properties with basic ``@Column`` mapping.
For the purposes of this tutorial, we will assume that you have a ``User``
class in your application and you would like to store an address in

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

@@ -488,7 +488,6 @@ classes. We'll store them in ``src/Bug.php`` and ``src/User.php``, respectively.
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="BugRepository")
* @ORM\Table(name="bugs")
*/
class Bug

View File

@@ -19,15 +19,14 @@
namespace Doctrine\ORM;
use Doctrine\Common\Persistence\Mapping\MappingException;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Cache\QueryCacheKey;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\Persistence\Mapping\MappingException;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
@@ -73,6 +72,7 @@ abstract class AbstractQuery
* The parameter map of this query.
*
* @var ArrayCollection|Parameter[]
* @psalm-var ArrayCollection<int, Parameter>
*/
protected $parameters;
@@ -241,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)
{
@@ -261,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)
{
@@ -322,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;
}
);
@@ -339,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) {
@@ -389,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)
{
@@ -469,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();
};
@@ -630,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.
*/
@@ -965,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();
@@ -982,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());
@@ -1069,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

@@ -25,8 +25,6 @@ use Doctrine\Common\Annotations\CachedReader;
use Doctrine\Common\Annotations\SimpleAnnotationReader;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache as CacheDriver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\Common\Proxy\AbstractProxyFactory;
use Doctrine\ORM\Cache\CacheConfiguration;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
@@ -39,6 +37,9 @@ use Doctrine\ORM\Mapping\NamingStrategy;
use Doctrine\ORM\Mapping\QuoteStrategy;
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
use Doctrine\ORM\Repository\RepositoryFactory;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Persistence\ObjectRepository;
use function interface_exists;
/**
* Configuration container for all configuration options of Doctrine.
@@ -441,6 +442,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $name
*
* @return string|null
* @psalm-return ?class-string
*/
public function getCustomStringFunction($name)
{
@@ -493,6 +495,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $name
*
* @return string|null
* @psalm-return ?class-string
*/
public function getCustomNumericFunction($name)
{
@@ -533,6 +536,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string|callable $className Class name or a callable that returns the function.
*
* @return void
*
* @psalm-param class-string|callable $className
*/
public function addCustomDatetimeFunction($name, $className)
{
@@ -545,6 +550,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $name
*
* @return string|null
*
* @psalm-return ?class-string $name
*/
public function getCustomDatetimeFunction($name)
{
@@ -566,6 +573,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param array $functions The map of custom DQL date/time functions.
*
* @return void
*
* @psalm-param array<string, string> $functions
*/
public function setCustomDatetimeFunctions(array $functions)
{
@@ -596,6 +605,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $modeName The hydration mode name.
*
* @return string|null The hydrator class name.
*
* @psalm-return ?class-string
*/
public function getCustomHydrationMode($modeName)
{
@@ -623,6 +634,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $cmfName
*
* @return void
*
* @psalm-param class-string $cmfName
*/
public function setClassMetadataFactoryName($cmfName)
{
@@ -631,6 +644,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* @return string
*
* @psalm-return class-string
*/
public function getClassMetadataFactoryName()
{
@@ -657,8 +672,10 @@ class Configuration extends \Doctrine\DBAL\Configuration
*
* @param string $name The name of the filter.
*
* @return string The class name of the filter, or null if it is not
* @return string|null The class name of the filter, or null if it is not
* defined.
*
* @psalm-return ?class-string
*/
public function getFilterClassName($name)
{
@@ -676,7 +693,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
*
* @return void
*
* @throws ORMException If not is a \Doctrine\Common\Persistence\ObjectRepository
* @throws ORMException If $classname is not an ObjectRepository.
*/
public function setDefaultRepositoryClassName($className)
{
@@ -695,6 +712,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @since 2.2
*
* @return string
*
* @psalm-return class-string
*/
public function getDefaultRepositoryClassName()
{
@@ -918,3 +937,5 @@ class Configuration extends \Doctrine\DBAL\Configuration
$this->_attributes['defaultQueryHints'][$name] = $value;
}
}
interface_exists(MappingDriver::class);

View File

@@ -21,7 +21,7 @@ namespace Doctrine\ORM\Decorator;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Common\Persistence\ObjectManagerDecorator;
use Doctrine\Persistence\ObjectManagerDecorator;
/**
* Base class for EntityManager decorators
@@ -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

@@ -28,7 +28,10 @@ use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Query\FilterCollection;
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;
@@ -325,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);
}
@@ -371,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
@@ -386,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);
@@ -546,9 +549,9 @@ use function trigger_error;
*
* @return void
*
* @throws ORMInvalidArgumentException if a non-null non-string value is given
* @throws \Doctrine\Common\Persistence\Mapping\MappingException if a $entityName is given, but that entity is not
* found in the mappings
* @throws ORMInvalidArgumentException If a non-null non-string value is given.
* @throws MappingException If a $entityName is given, but that entity is not
* found in the mappings.
*/
public function clear($entityName = null)
{
@@ -729,7 +732,7 @@ use function trigger_error;
*
* @param string $entityName The name of the entity.
*
* @return \Doctrine\Common\Persistence\ObjectRepository|\Doctrine\ORM\EntityRepository The repository class.
* @return ObjectRepository|EntityRepository The repository class.
*/
public function getRepository($entityName)
{

View File

@@ -19,8 +19,8 @@
namespace Doctrine\ORM;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\ObjectManager;
/**
* EntityManager interface

View File

@@ -19,11 +19,11 @@
namespace Doctrine\ORM;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\Selectable;
use Doctrine\Common\Inflector\Inflector;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\Common\Collections\Selectable;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Persistence\ObjectRepository;
/**
* An EntityRepository serves as a repository for entities with generic as well as

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
use Doctrine\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
/**
* Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClassMetadataEventArgs;
use Doctrine\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClassMetadataEventArgs;
/**
* Class that holds event arguments for a loadMetadata event.

View File

@@ -19,9 +19,10 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\Persistence\Event\ManagerEventArgs;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Persistence\Event\ManagerEventArgs;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\ObjectManager;
use function interface_exists;
/**
* Class that holds event arguments for a `onClassMetadataNotFound` event.
@@ -84,3 +85,4 @@ class OnClassMetadataNotFoundEventArgs extends ManagerEventArgs
}
}
interface_exists(ClassMetadata::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

@@ -19,9 +19,6 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory;
use Doctrine\Common\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
use Doctrine\Common\Persistence\Mapping\ReflectionService;
use Doctrine\DBAL\Platforms;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
@@ -30,8 +27,14 @@ use Doctrine\ORM\Events;
use Doctrine\ORM\Id\BigIntegerIdentityGenerator;
use Doctrine\ORM\Id\IdentityGenerator;
use Doctrine\ORM\ORMException;
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;
/**
* The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
@@ -57,7 +60,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
private $targetPlatform;
/**
* @var \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver
* @var MappingDriver
*/
private $driver;
@@ -276,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
@@ -402,7 +410,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass)
{
foreach ($parentClass->fieldMappings as $mapping) {
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass && ! $parentClass->isEmbeddedClass) {
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
$mapping['inherited'] = $parentClass->name;
}
if (! isset($mapping['declared'])) {
@@ -470,6 +478,10 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
private function addNestedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass, $prefix)
{
foreach ($subClass->embeddedClasses as $property => $embeddableClass) {
if (isset($embeddableClass['inherited'])) {
continue;
}
$embeddableMetadata = $this->getMetadataFor($embeddableClass['class']);
$parentClass->mapEmbedded(
@@ -777,9 +789,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
*/
protected function isEntity(ClassMetadataInterface $class)
{
assert($class instanceof ClassMetadata);
return $class->isMappedSuperclass === false && $class->isEmbeddedClass === false;
return isset($class->isMappedSuperclass) && $class->isMappedSuperclass === false;
}
/**
@@ -794,3 +804,6 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
return $this->targetPlatform;
}
}
interface_exists(ClassMetadataInterface::class);
interface_exists(ReflectionService::class);

View File

@@ -20,14 +20,18 @@
namespace Doctrine\ORM\Mapping;
use BadMethodCallException;
use Doctrine\Instantiator\Instantiator;
use InvalidArgumentException;
use RuntimeException;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use ReflectionClass;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Instantiator\Instantiator;
use Doctrine\ORM\Cache\CacheException;
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
@@ -251,7 +255,8 @@ class ClassMetadataInfo implements ClassMetadata
* The name of the custom repository class used for the entity class.
* (Optional).
*
* @var string
* @var string|null
* @psalm-var ?class-string
*/
public $customRepositoryClassName;
@@ -392,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 = [];
@@ -639,7 +646,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* The ReflectionProperty instances of the mapped class.
*
* @var \ReflectionProperty[]
* @var ReflectionProperty[]|null[]
*/
public $reflFields = [];
@@ -666,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()
{
@@ -678,7 +687,7 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param string $name
*
* @return \ReflectionProperty
* @return ReflectionProperty
*/
public function getReflectionProperty($name)
{
@@ -688,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.
*/
@@ -804,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()
{
@@ -914,7 +923,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Restores some state that can not be serialized/unserialized.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
* @param ReflectionService $reflService
*
* @return void
*/
@@ -975,7 +984,7 @@ class ClassMetadataInfo implements ClassMetadata
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService The reflection service.
* @param ReflectionService $reflService The reflection service.
*
* @return void
*/
@@ -1037,7 +1046,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Validates lifecycle callbacks.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
* @param ReflectionService $reflService
*
* @return void
*
@@ -1095,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)
{
@@ -1444,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)
{
@@ -1564,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)
{
@@ -1655,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)
{
@@ -1682,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)
{
@@ -1861,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)
{
@@ -2216,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']]);
@@ -2297,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] === '`') {
@@ -2523,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;
@@ -2625,6 +2682,8 @@ class ClassMetadataInfo implements ClassMetadata
* @param string $repositoryClassName The class name of the custom mapper.
*
* @return void
*
* @psalm-param class-string $repositoryClassName
*/
public function setCustomRepositoryClass($repositoryClassName)
{
@@ -3253,6 +3312,8 @@ class ClassMetadataInfo implements ClassMetadata
* @param string|null $className
*
* @return string|null null if the input value is null
*
* @psalm-param ?class-string $className
*/
public function fullyQualifiedClassName($className)
{

View File

@@ -30,6 +30,8 @@ class DefaultEntityListenerResolver implements EntityListenerResolver
{
/**
* @var array Map to store entity listener instances.
*
* @psalm-var array<class-string, object>
*/
private $instances = [];

View File

@@ -20,12 +20,13 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
use Doctrine\ORM\Events;
use Doctrine\ORM\Mapping;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
use function interface_exists;
/**
* The AnnotationDriver reads the mapping metadata from docblock annotations.
@@ -39,12 +40,12 @@ use Doctrine\ORM\Mapping\MappingException;
class AnnotationDriver extends AbstractAnnotationDriver
{
/**
* {@inheritDoc}
* @var int[]
* @psalm-var array<class-string, int>
*/
protected $entityAnnotationClasses = [
Mapping\Entity::class => 1,
Mapping\MappedSuperclass::class => 2,
Mapping\Embeddable::class => 3,
];
/**
@@ -274,11 +275,8 @@ class AnnotationDriver extends AbstractAnnotationDriver
}
// Evaluate annotations on properties/fields
/* @var $property \ReflectionProperty */
foreach ($class->getProperties() as $property) {
if ($metadata->isMappedSuperclass && ! $property->isPrivate()
||
$metadata->isEmbeddedClass && $property->getDeclaringClass()->getName() !== $class->getName()
||
$metadata->isInheritedField($property->name)
||
@@ -507,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);
@@ -527,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]);
@@ -560,7 +556,7 @@ class AnnotationDriver extends AbstractAnnotationDriver
*
* @param \ReflectionMethod $method
*
* @return array
* @return callable[]
*/
private function getMethodCallbacks(\ReflectionMethod $method)
{
@@ -608,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)
{
@@ -628,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)
{
@@ -674,3 +693,5 @@ class AnnotationDriver extends AbstractAnnotationDriver
return new self($reader, $paths);
}
}
interface_exists(ClassMetadata::class);

View File

@@ -20,15 +20,17 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Inflector\Inflector;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
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;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use function interface_exists;
use function preg_replace;
/**
@@ -387,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)
{
@@ -487,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)
{
@@ -501,7 +521,7 @@ class DatabaseDriver implements MappingDriver
*
* @param \Doctrine\DBAL\Schema\Table $table
*
* @return array
* @return string[]
*/
private function getTablePrimaryKeys(Table $table)
{
@@ -555,3 +575,5 @@ class DatabaseDriver implements MappingDriver
return Inflector::camelize($columnName);
}
}
interface_exists(ClassMetadata::class);

View File

@@ -19,12 +19,12 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
/**
* {@inheritDoc}
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain instead
* @deprecated this driver will be removed. Use Doctrine\Persistence\Mapping\Driver\MappingDriverChain instead
*/
class DriverChain extends MappingDriverChain
{

View File

@@ -19,12 +19,12 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver as CommonPHPDriver;
use Doctrine\Persistence\Mapping\Driver\PHPDriver as CommonPHPDriver;
/**
* {@inheritDoc}
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver instead
* @deprecated this driver will be removed. Use Doctrine\Persistence\Mapping\Driver\PHPDriver instead
*/
class PHPDriver extends CommonPHPDriver
{

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator;
use Doctrine\Persistence\Mapping\Driver\SymfonyFileLocator;
/**
* XmlDriver that additionally looks for mapping information in a global file.

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator;
use Doctrine\Persistence\Mapping\Driver\SymfonyFileLocator;
/**
* YamlDriver that additionally looks for mapping information in a global file.

View File

@@ -19,12 +19,12 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver as CommonStaticPHPDriver;
use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver as CommonStaticPHPDriver;
/**
* {@inheritDoc}
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver instead
* @deprecated this driver will be removed. Use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver instead
*/
class StaticPHPDriver extends CommonStaticPHPDriver
{

View File

@@ -20,12 +20,13 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Collections\Criteria;
use SimpleXMLElement;
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\ORM\Mapping\ClassMetadata as Metadata;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\FileDriver;
use SimpleXMLElement;
use function interface_exists;
/**
* XmlDriver is a metadata driver that enables mapping through XML files.
@@ -670,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());
@@ -705,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)
{
@@ -734,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 = [
@@ -794,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)
{
@@ -820,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
@@ -879,3 +903,5 @@ class XmlDriver extends FileDriver
return ($flag == "true" || $flag == "1");
}
}
interface_exists(ClassMetadata::class);

View File

@@ -19,12 +19,13 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
use Doctrine\ORM\Mapping\ClassMetadata as Metadata;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\FileDriver;
use Symfony\Component\Yaml\Yaml;
use function interface_exists;
use function trigger_error;
/**
@@ -683,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)
{
@@ -725,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)
{
@@ -786,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)
{
@@ -817,3 +845,5 @@ class YamlDriver extends FileDriver
return Yaml::parse(file_get_contents($file));
}
}
interface_exists(ClassMetadata::class);

View File

@@ -34,6 +34,8 @@ interface EntityListenerResolver
* @param string $className The fully-qualified class name
*
* @return void
*
* @psalm-param class-string $className
*/
function clear($className = null);
@@ -43,6 +45,8 @@ interface EntityListenerResolver
* @param string $className The fully-qualified class name
*
* @return object An entity listener
*
* @psalm-param class-string $className
*/
function resolve($className);

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Mapping\Reflection;
use Doctrine\Common\Persistence\Mapping\ReflectionService;
use Doctrine\Persistence\Mapping\ReflectionService;
use ReflectionClass;
use ReflectionProperty;
@@ -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

@@ -20,7 +20,9 @@
namespace Doctrine\ORM;
use Doctrine\Common\Cache\Cache as CacheDriver;
use Doctrine\Persistence\ObjectRepository;
use Exception;
use function sprintf;
/**
* Base exception class for all ORM exceptions.
@@ -108,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)
{
@@ -295,7 +297,11 @@ class ORMException extends Exception
*/
public static function invalidEntityRepository($className)
{
return new self("Invalid repository class '".$className."'. It must be a Doctrine\Common\Persistence\ObjectRepository.");
return new self(sprintf(
"Invalid repository class '%s'. It must be a %s.",
$className,
ObjectRepository::class
));
}
/**

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;
@@ -92,7 +93,6 @@ class BasicEntityPersister implements EntityPersister
*/
static private $comparisonMap = [
Comparison::EQ => '= %s',
Comparison::IS => '= %s',
Comparison::NEQ => '!= %s',
Comparison::GT => '> %s',
Comparison::GTE => '>= %s',
@@ -361,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 = [];
@@ -443,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;
}
@@ -602,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)
{
@@ -626,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'];
@@ -689,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)
{
@@ -714,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) {
@@ -806,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);
@@ -820,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);
@@ -837,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);
@@ -863,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));
}
@@ -885,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);
@@ -955,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);
}
/**
@@ -1030,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);
}
@@ -1134,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 = [];
@@ -1419,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()
{
@@ -1536,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);
}
@@ -1544,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
*/
@@ -1656,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])) {
@@ -1753,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);
}
/**
@@ -1813,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);
}
@@ -1847,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)
{
@@ -1874,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)
{
@@ -1989,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);
@@ -2026,7 +2071,9 @@ class BasicEntityPersister implements EntityPersister
}
/**
* {@inheritdoc}
* @param string $columnName
*
* @return string
*/
public function getSQLColumnAlias($columnName)
{

View File

@@ -18,8 +18,9 @@
*/
namespace Doctrine\ORM\Persisters\Entity;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\Mapping\ClassMetadata;
/**
* A swappable persister context to use as a container for the current

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

@@ -19,7 +19,6 @@
namespace Doctrine\ORM\Proxy;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Proxy\AbstractProxyFactory;
use Doctrine\Common\Proxy\Proxy as BaseProxy;
use Doctrine\Common\Proxy\ProxyDefinition;
@@ -29,6 +28,8 @@ use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use Doctrine\ORM\EntityNotFoundException;
use Doctrine\ORM\Utility\IdentifierFlattener;
use Doctrine\Persistence\Mapping\ClassMetadata;
use function interface_exists;
/**
* This factory is used to create proxy objects for entities at runtime.
@@ -118,12 +119,11 @@ class ProxyFactory extends AbstractProxyFactory
/**
* Creates a closure capable of initializing a proxy
*
* @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
* @param \Doctrine\ORM\Persisters\Entity\EntityPersister $entityPersister
*
* @return \Closure
*
* @throws \Doctrine\ORM\EntityNotFoundException
*
* @psalm-return \Closure(BaseProxy):void
*/
private function createInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister)
{
@@ -172,12 +172,11 @@ class ProxyFactory extends AbstractProxyFactory
/**
* Creates a closure capable of finalizing state a cloned proxy
*
* @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
* @param \Doctrine\ORM\Persisters\Entity\EntityPersister $entityPersister
*
* @return \Closure
*
* @throws \Doctrine\ORM\EntityNotFoundException
*
* @psalm-return \Closure(BaseProxy):void
*/
private function createCloner(ClassMetadata $classMetadata, EntityPersister $entityPersister)
{
@@ -211,3 +210,5 @@ class ProxyFactory extends AbstractProxyFactory
};
}
}
interface_exists(ClassMetadata::class);

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

@@ -20,6 +20,7 @@
namespace Doctrine\ORM\Query;
use Doctrine\ORM\EntityManagerInterface;
use function assert;
/**
* Collection class for all the query filters.
@@ -110,6 +111,8 @@ class FilterCollection
if ( ! $this->isEnabled($name)) {
$filterClass = $this->config->getFilterClassName($name);
assert($filterClass !== null);
$this->enabledFilters[$name] = new $filterClass($this->em);
// Keep the enabled filters sorted for the hash

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;
@@ -42,6 +50,8 @@ class Parser
* READ-ONLY: Maps BUILT-IN string function names to AST class names.
*
* @var array
*
* @psalm-var array<string, class-string<Functions\FunctionNode>>
*/
private static $_STRING_FUNCTIONS = [
'concat' => Functions\ConcatFunction::class,
@@ -56,6 +66,8 @@ class Parser
* READ-ONLY: Maps BUILT-IN numeric function names to AST class names.
*
* @var array
*
* @psalm-var array<string, class-string<Functions\FunctionNode>>
*/
private static $_NUMERIC_FUNCTIONS = [
'length' => Functions\LengthFunction::class,
@@ -80,6 +92,8 @@ class Parser
* READ-ONLY: Maps BUILT-IN datetime function names to AST class names.
*
* @var array
*
* @psalm-var array<string, class-string<Functions\FunctionNode>>
*/
private static $_DATETIME_FUNCTIONS = [
'current_date' => Functions\CurrentDateFunction::class,
@@ -171,7 +185,7 @@ class Parser
/**
* The custom last tree walker, if any, that is responsible for producing the output.
*
* @var TreeWalker
* @var class-string<TreeWalker>
*/
private $customOutputWalker;
@@ -251,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()
{
@@ -418,6 +430,8 @@ class Parser
return;
}
assert($AST instanceof AST\SelectStatement);
foreach ($this->queryComponents as $dqlAlias => $qComp) {
if ( ! isset($this->identVariableExpressions[$dqlAlias])) {
continue;
@@ -616,7 +630,7 @@ class Parser
/**
* Validates that the given <tt>NewObjectExpression</tt>.
*
* @param \Doctrine\ORM\Query\AST\SelectClause $AST
* @param SelectStatement $AST
*
* @return void
*/
@@ -833,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()
{
@@ -872,7 +884,7 @@ class Parser
/**
* SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
*
* @return \Doctrine\ORM\Query\AST\SelectStatement
* @return SelectStatement
*/
public function SelectStatement()
{
@@ -889,7 +901,7 @@ class Parser
/**
* UpdateStatement ::= UpdateClause [WhereClause]
*
* @return \Doctrine\ORM\Query\AST\UpdateStatement
* @return UpdateStatement
*/
public function UpdateStatement()
{
@@ -903,7 +915,7 @@ class Parser
/**
* DeleteStatement ::= DeleteClause [WhereClause]
*
* @return \Doctrine\ORM\Query\AST\DeleteStatement
* @return DeleteStatement
*/
public function DeleteStatement()
{
@@ -1072,7 +1084,7 @@ class Parser
*
* @param integer $expectedTypes
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function PathExpression($expectedTypes)
{
@@ -1108,7 +1120,7 @@ class Parser
/**
* AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function AssociationPathExpression()
{
@@ -1121,7 +1133,7 @@ class Parser
/**
* SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function SingleValuedPathExpression()
{
@@ -1134,7 +1146,7 @@ class Parser
/**
* StateFieldPathExpression ::= IdentificationVariable "." StateField
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function StateFieldPathExpression()
{
@@ -1144,7 +1156,7 @@ class Parser
/**
* SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function SingleValuedAssociationPathExpression()
{
@@ -1154,7 +1166,7 @@ class Parser
/**
* CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
*
* @return \Doctrine\ORM\Query\AST\PathExpression
* @return PathExpression
*/
public function CollectionValuedPathExpression()
{
@@ -1419,7 +1431,7 @@ class Parser
/**
* Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
*
* @return \Doctrine\ORM\Query\AST\Subselect
* @return Subselect
*/
public function Subselect()
{
@@ -1458,7 +1470,7 @@ class Parser
/**
* GroupByItem ::= IdentificationVariable | ResultVariable | SingleValuedPathExpression
*
* @return string | \Doctrine\ORM\Query\AST\PathExpression
* @return string|PathExpression
*/
public function GroupByItem()
{
@@ -1501,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;
@@ -1517,6 +1525,10 @@ class Parser
$expr = $this->ScalarExpression();
break;
case $this->isFunction():
$expr = $this->FunctionDeclaration();
break;
default:
$expr = $this->ResultVariable();
break;
@@ -1555,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()
{
@@ -1577,7 +1589,7 @@ class Parser
/**
* IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {Join}*
*
* @return \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
* @return IdentificationVariableDeclaration
*/
public function IdentificationVariableDeclaration()
{
@@ -1616,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()
{
@@ -1760,7 +1771,7 @@ class Parser
/**
* JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy]
*
* @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression
* @return AST\JoinAssociationDeclaration
*/
public function JoinAssociationDeclaration()
{
@@ -2386,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()
{
@@ -2411,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()
{
@@ -2436,7 +2447,7 @@ class Parser
/**
* ConditionalFactor ::= ["NOT"] ConditionalPrimary
*
* @return \Doctrine\ORM\Query\AST\ConditionalFactor
* @return AST\ConditionalFactor|AST\ConditionalPrimary
*/
public function ConditionalFactor()
{
@@ -2683,7 +2694,7 @@ class Parser
/**
* InParameter ::= Literal | InputParameter
*
* @return string | \Doctrine\ORM\Query\AST\InputParameter
* @return AST\InputParameter|AST\Literal
*/
public function InParameter()
{
@@ -2867,8 +2878,7 @@ class Parser
/**
* StringExpression ::= StringPrimary | ResultVariable | "(" Subselect ")"
*
* @return \Doctrine\ORM\Query\AST\Subselect |
* string
* @return Subselect|string
*/
public function StringExpression()
{
@@ -2941,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()
{
@@ -2958,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

@@ -27,6 +27,7 @@ use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\Query;
use Doctrine\ORM\Utility\HierarchyDiscriminatorResolver;
use Doctrine\ORM\Utility\PersisterHelper;
use function trim;
/**
* The SqlWalker is a TreeWalker that walks over a DQL AST and constructs
@@ -107,7 +108,7 @@ class SqlWalker implements TreeWalker
private $conn;
/**
* @var \Doctrine\ORM\AbstractQuery
* @var Query
*/
private $query;
@@ -141,6 +142,8 @@ class SqlWalker implements TreeWalker
* Map of all components/classes that appear in the DQL query.
*
* @var array
*
* @psalm-var array<string, array{metadata: ClassMetadata, token: array, relation: mixed[], parent: string}>
*/
private $queryComponents;
@@ -198,7 +201,7 @@ class SqlWalker implements TreeWalker
/**
* Gets the Query instance used by the walker.
*
* @return Query.
* @return Query
*/
public function getQuery()
{
@@ -231,6 +234,8 @@ class SqlWalker implements TreeWalker
* @param string $dqlAlias The DQL alias.
*
* @return array
*
* @psalm-return array{metadata: ClassMetadata}
*/
public function getQueryComponent($dqlAlias)
{
@@ -361,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
@@ -656,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:
@@ -1400,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;
@@ -1521,7 +1546,7 @@ class SqlWalker implements TreeWalker
/**
* @param \Doctrine\ORM\Query\AST\ParenthesisExpression $parenthesisExpression
*
* @return string.
* @return string
*/
public function walkParenthesisExpression(AST\ParenthesisExpression $parenthesisExpression)
{
@@ -1553,12 +1578,20 @@ class SqlWalker implements TreeWalker
break;
case ($e instanceof AST\PathExpression):
$dqlAlias = $e->identificationVariable;
$qComp = $this->queryComponents[$dqlAlias];
$class = $qComp['metadata'];
$fieldType = $class->fieldMappings[$e->field]['type'];
$dqlAlias = $e->identificationVariable;
$qComp = $this->queryComponents[$dqlAlias];
$class = $qComp['metadata'];
$fieldType = $class->fieldMappings[$e->field]['type'];
$fieldName = $e->field;
$fieldMapping = $class->fieldMappings[$fieldName];
$col = trim($e->dispatch($this));
$sqlSelectExpressions[] = trim($e->dispatch($this)) . ' AS ' . $columnAlias;
if (isset($fieldMapping['requireSQLConversion'])) {
$type = Type::getType($fieldType);
$col = $type->convertToPHPValueSQL($col, $this->platform);
}
$sqlSelectExpressions[] = $col . ' AS ' . $columnAlias;
break;
case ($e instanceof AST\Literal):
@@ -2067,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,13 +19,16 @@
namespace Doctrine\ORM\Query;
use Doctrine\ORM\AbstractQuery;
/**
*
* @template-implements \Iterator<TreeWalker>
* @template-implements \ArrayAccess<int, TreeWalker>
*/
class TreeWalkerChainIterator implements \Iterator, \ArrayAccess
{
/**
* @var TreeWalker[]
* @var class-string<TreeWalker>[]
*/
private $walkers = [];
/**
@@ -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)
{

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