mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 06:52:09 +01:00
Compare commits
210 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d84a49980 | ||
|
|
bb64fc953d | ||
|
|
e0eb82a3b1 | ||
|
|
79cdcde9ec | ||
|
|
f4524a8bb0 | ||
|
|
d810ea4111 | ||
|
|
107ba93d79 | ||
|
|
706670215d | ||
|
|
ab2b4987b3 | ||
|
|
717ef9106c | ||
|
|
ccae8f7176 | ||
|
|
da18985aca | ||
|
|
1e2ed07731 | ||
|
|
424241f29c | ||
|
|
8230afcde9 | ||
|
|
7cffba8743 | ||
|
|
7e5fe79349 | ||
|
|
efd25484f4 | ||
|
|
271f3480c8 | ||
|
|
aab589b596 | ||
|
|
190218b267 | ||
|
|
181114f2c7 | ||
|
|
3689b76a86 | ||
|
|
75fe18ea5f | ||
|
|
6c73a6b720 | ||
|
|
775d91c2a3 | ||
|
|
64c3f68734 | ||
|
|
2a2a0b2980 | ||
|
|
a438e90046 | ||
|
|
6a670d7d6d | ||
|
|
765521d257 | ||
|
|
5ced62bf83 | ||
|
|
93867f8d77 | ||
|
|
d95e03ba66 | ||
|
|
825ceb6b7a | ||
|
|
de2e2a1d74 | ||
|
|
6780a963f7 | ||
|
|
4d172e2591 | ||
|
|
21a98234d0 | ||
|
|
8a9954e46c | ||
|
|
527fff53cc | ||
|
|
70fb1ecd78 | ||
|
|
73ec483e9d | ||
|
|
8d67eec812 | ||
|
|
a418cf6418 | ||
|
|
6138afdca9 | ||
|
|
dafe298ce5 | ||
|
|
58b8130ea1 | ||
|
|
a705f526fb | ||
|
|
a9b6b72017 | ||
|
|
cd905fff77 | ||
|
|
eb700405be | ||
|
|
9273057649 | ||
|
|
e04a79526e | ||
|
|
d157a6cbeb | ||
|
|
ca57222010 | ||
|
|
9bb2bf0cce | ||
|
|
445796af0e | ||
|
|
ab93285284 | ||
|
|
a692670469 | ||
|
|
58677c29b4 | ||
|
|
9a0fcb5a86 | ||
|
|
8104c65d6c | ||
|
|
a64d254d07 | ||
|
|
fdad48278b | ||
|
|
fc94127d7f | ||
|
|
dea3e5df44 | ||
|
|
5d7d3e99a0 | ||
|
|
3bc1096fd0 | ||
|
|
a2f01f7ccc | ||
|
|
401db453a2 | ||
|
|
6e59ec8f16 | ||
|
|
87e491465a | ||
|
|
8b588eceb2 | ||
|
|
edce36598f | ||
|
|
20c46035d1 | ||
|
|
324aacfb54 | ||
|
|
1edfcabead | ||
|
|
2785cde792 | ||
|
|
d67e3e8b1b | ||
|
|
d629c4e487 | ||
|
|
4a4226213f | ||
|
|
0ce1440884 | ||
|
|
9aa28b4e33 | ||
|
|
5c2b6870bf | ||
|
|
4389b2c188 | ||
|
|
e481d9880b | ||
|
|
85528f28e2 | ||
|
|
5873242fb5 | ||
|
|
c9e41d0aa7 | ||
|
|
f37c12834d | ||
|
|
041404e8b3 | ||
|
|
bfc68b3aba | ||
|
|
1e628370c4 | ||
|
|
ae2b9b1921 | ||
|
|
419df77a09 | ||
|
|
d6f6b2e97c | ||
|
|
75d5adf599 | ||
|
|
cfd6fadf9c | ||
|
|
2bf7916c52 | ||
|
|
253fd10cc0 | ||
|
|
2c956d55f2 | ||
|
|
3db992e953 | ||
|
|
6fc9b3ab16 | ||
|
|
2d833a5e86 | ||
|
|
a416a9a8b2 | ||
|
|
4d763ca4c9 | ||
|
|
398d74deaa | ||
|
|
3314322929 | ||
|
|
ce93817bf7 | ||
|
|
50992eafa2 | ||
|
|
9ccb8837e7 | ||
|
|
d959744c0a | ||
|
|
0264ba1759 | ||
|
|
8332fa1855 | ||
|
|
4fae126459 | ||
|
|
2d9b935183 | ||
|
|
4804f602f8 | ||
|
|
3d17290eb5 | ||
|
|
8420d24f90 | ||
|
|
52f2b37921 | ||
|
|
16751d210f | ||
|
|
686f508576 | ||
|
|
00ef1eba90 | ||
|
|
3843eee5cb | ||
|
|
f576e6c41f | ||
|
|
c79d2e0dc2 | ||
|
|
33b8d020a7 | ||
|
|
1b2daac25d | ||
|
|
977985f756 | ||
|
|
0c36f87935 | ||
|
|
e8f265d480 | ||
|
|
7bcbad076d | ||
|
|
57496e32fd | ||
|
|
797bfc53c4 | ||
|
|
8c47dcb6fc | ||
|
|
6347190886 | ||
|
|
9162f3519d | ||
|
|
fc9314d9f5 | ||
|
|
26806d08eb | ||
|
|
6a827d5b61 | ||
|
|
7d77984306 | ||
|
|
ec93014713 | ||
|
|
c83094bde0 | ||
|
|
982d1519db | ||
|
|
f7c04ae537 | ||
|
|
f9a4258ded | ||
|
|
eb9f11bf96 | ||
|
|
2b8cb9de79 | ||
|
|
570abb5bad | ||
|
|
855244fd10 | ||
|
|
c62977412c | ||
|
|
98e557b68e | ||
|
|
3a32c00dcf | ||
|
|
1dde2c9e8e | ||
|
|
adfd010a78 | ||
|
|
1bc4e1f594 | ||
|
|
21680df9bd | ||
|
|
19aa3c125c | ||
|
|
e9e012a037 | ||
|
|
d1db0655ac | ||
|
|
2d643e6b7b | ||
|
|
4d6b1f3e63 | ||
|
|
d9c30e34c4 | ||
|
|
90c1ee0bd0 | ||
|
|
cfcca3a63c | ||
|
|
af0949adab | ||
|
|
cdb652ad87 | ||
|
|
4fb1ebfc10 | ||
|
|
46c1b57560 | ||
|
|
fdbbf7edd1 | ||
|
|
2fed8204c1 | ||
|
|
76f03b5db0 | ||
|
|
9fef4e86e4 | ||
|
|
4781dc03e9 | ||
|
|
cc5f84ac22 | ||
|
|
023e94661a | ||
|
|
b59fc23f86 | ||
|
|
d71dd5d94f | ||
|
|
63513e9a05 | ||
|
|
c802bc46a5 | ||
|
|
506bf0ee12 | ||
|
|
a36809db72 | ||
|
|
5b00d7ba5e | ||
|
|
b22604352d | ||
|
|
00c6b1bc60 | ||
|
|
4b0d86ee92 | ||
|
|
3707c39124 | ||
|
|
fe72b00df2 | ||
|
|
79a7ecc92f | ||
|
|
16df8bfe0d | ||
|
|
b37ceaa9f7 | ||
|
|
c41fdbce8a | ||
|
|
7526adc80a | ||
|
|
766eb693fb | ||
|
|
f9e2ae3488 | ||
|
|
6bf2ff5d10 | ||
|
|
27fcc01d81 | ||
|
|
3ac1f8e680 | ||
|
|
b63db53552 | ||
|
|
bed8186573 | ||
|
|
f08ff83d0a | ||
|
|
7c8c0906be | ||
|
|
167cb44ea1 | ||
|
|
5d74bdb240 | ||
|
|
ca38249f6c | ||
|
|
6a74f373b9 | ||
|
|
1c45e1b744 | ||
|
|
5612790307 | ||
|
|
17bc627bf2 |
49
.doctrine-project.json
Normal file
49
.doctrine-project.json
Normal 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
4
.gitattributes
vendored
@@ -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
111
.github/workflows/ci.yml
vendored
Normal 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"
|
||||
55
.github/workflows/release-on-milestone-closed.yml
vendored
Normal file
55
.github/workflows/release-on-milestone-closed.yml
vendored
Normal 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 }}
|
||||
@@ -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
|
||||
40
.travis.yml
40
.travis.yml
@@ -6,8 +6,7 @@ php:
|
||||
- 7.1
|
||||
- 7.2
|
||||
- 7.3
|
||||
- 7.4snapshot
|
||||
- nightly
|
||||
- 7.4
|
||||
|
||||
env:
|
||||
- DB=sqlite
|
||||
@@ -18,7 +17,7 @@ before_install:
|
||||
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{,.disabled} || echo "xdebug not available"
|
||||
- composer self-update
|
||||
|
||||
install: travis_retry composer update --prefer-dist
|
||||
install: travis_retry composer validate --strict && composer update --prefer-dist
|
||||
|
||||
script:
|
||||
- if [[ "$DB" == "mysql" || "$DB" == "mariadb" ]]; then mysql -e "CREATE SCHEMA doctrine_tests; GRANT ALL PRIVILEGES ON doctrine_tests.* to travis@'%'"; fi
|
||||
@@ -55,7 +54,7 @@ jobs:
|
||||
- stage: Test
|
||||
dist: xenial
|
||||
env: DB=mysql MYSQL_VERSION=5.7
|
||||
php: nightly
|
||||
php: 7.4
|
||||
services:
|
||||
- mysql
|
||||
before_script:
|
||||
@@ -81,49 +80,24 @@ 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
|
||||
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
|
||||
|
||||
- stage: Code Quality
|
||||
if: NOT type = pull_request
|
||||
env: DB=none CODING_STANDARDS
|
||||
php: 7.1
|
||||
php: 7.4
|
||||
install: travis_retry composer install --prefer-dist
|
||||
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:
|
||||
- php: nightly
|
||||
- stage: Code Quality
|
||||
env: DB=none CODING_STANDARDS
|
||||
|
||||
|
||||
18
README.md
18
README.md
@@ -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
|
||||
|
||||
156
UPGRADE.md
156
UPGRADE.md
@@ -1,3 +1,145 @@
|
||||
# Upgrade to 2.7
|
||||
|
||||
## Added `Doctrine\ORM\AbstractQuery#enableResultCache()` and `Doctrine\ORM\AbstractQuery#disableResultCache()` methods
|
||||
|
||||
Method `Doctrine\ORM\AbstractQuery#useResultCache()` which could be used for both enabling and disabling the cache
|
||||
(depending on passed flag) was split into two.
|
||||
|
||||
## Minor BC BREAK: paginator output walkers aren't be called anymore on sub-queries for queries without max results
|
||||
|
||||
To optimize DB interaction, `Doctrine\ORM\Tools\Pagination\Paginator` no longer fetches identifiers to be able to
|
||||
perform the pagination with join collections when max results isn't set in the query.
|
||||
|
||||
## Minor BC BREAK: tables filtered with `schema_filter` are no longer created
|
||||
|
||||
When generating schema diffs, if a source table is filtered out by a `schema_filter` expression, then a `CREATE TABLE` was
|
||||
always generated, even if the table already existed. This has been changed in this release and the table will no longer
|
||||
be created.
|
||||
|
||||
## Deprecated number unaware `Doctrine\ORM\Mapping\UnderscoreNamingStrategy`
|
||||
|
||||
In the last patch of the `v2.6.x` series, we fixed a bug that was not converting names properly when they had numbers
|
||||
(e.g.: `base64Encoded` was wrongly converted to `base64encoded` instead of `base64_encoded`).
|
||||
|
||||
In order to not break BC we've introduced a way to enable the fixed behavior using a boolean constructor argument. This
|
||||
argument will be removed in 3.0 and the default behavior will be the fixed one.
|
||||
|
||||
## Deprecated: `Doctrine\ORM\AbstractQuery#useResultCache()`
|
||||
|
||||
Method `Doctrine\ORM\AbstractQuery#useResultCache()` is deprecated because it is split into `enableResultCache()`
|
||||
and `disableResultCache()`. It will be removed in 3.0.
|
||||
|
||||
## Deprecated code generators and related console commands
|
||||
|
||||
These console commands have been deprecated:
|
||||
|
||||
* `orm:convert-mapping`
|
||||
* `orm:generate:entities`
|
||||
* `orm:generate-repositories`
|
||||
|
||||
These classes have been deprecated:
|
||||
|
||||
* `Doctrine\ORM\Tools\EntityGenerator`
|
||||
* `Doctrine\ORM\Tools\EntityRepositoryGenerator`
|
||||
|
||||
Whole Doctrine\ORM\Tools\Export namespace with all its members have been deprecated as well.
|
||||
|
||||
## Deprecated `Doctrine\ORM\Proxy\Proxy` marker interface
|
||||
|
||||
Proxy objects in Doctrine ORM 3.0 will no longer implement `Doctrine\ORM\Proxy\Proxy` nor
|
||||
`Doctrine\Persistence\Proxy`: instead, they implement
|
||||
`ProxyManager\Proxy\GhostObjectInterface`.
|
||||
|
||||
These related classes have been deprecated:
|
||||
|
||||
* `Doctrine\ORM\Proxy\ProxyFactory`
|
||||
* `Doctrine\ORM\Proxy\Autoloader` - we suggest using the composer autoloader instead
|
||||
|
||||
These methods have been deprecated:
|
||||
|
||||
* `Doctrine\ORM\Configuration#getAutoGenerateProxyClasses()`
|
||||
* `Doctrine\ORM\Configuration#getProxyDir()`
|
||||
* `Doctrine\ORM\Configuration#getProxyNamespace()`
|
||||
|
||||
## Deprecated `Doctrine\ORM\Version`
|
||||
|
||||
The `Doctrine\ORM\Version` class is now deprecated and will be removed in Doctrine ORM 3.0:
|
||||
please refrain from checking the ORM version at runtime or use
|
||||
[ocramius/package-versions](https://github.com/Ocramius/PackageVersions/).
|
||||
|
||||
## Deprecated `EntityManager#merge()` and `EntityManager#detach()` methods
|
||||
|
||||
Merge and detach semantics were a poor fit for the PHP "share-nothing" architecture.
|
||||
In addition to that, merging/detaching caused multiple issues with data integrity
|
||||
in the managed entity graph, which was constantly spawning more edge-case bugs/scenarios.
|
||||
|
||||
The following API methods were therefore deprecated:
|
||||
|
||||
* `EntityManager#merge()`
|
||||
* `EntityManager#detach()`
|
||||
* `UnitOfWork#merge()`
|
||||
* `UnitOfWork#detach()`
|
||||
|
||||
Users are encouraged to migrate `EntityManager#detach()` calls to `EntityManager#clear()`.
|
||||
|
||||
In order to maintain performance on batch processing jobs, it is endorsed to enable
|
||||
the second level cache (http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second-level-cache.html)
|
||||
on entities that are frequently reused across multiple `EntityManager#clear()` calls.
|
||||
|
||||
An alternative to `EntityManager#merge()` will not be provided by ORM 3.0, since the merging
|
||||
semantics should be part of the business domain rather than the persistence domain of an
|
||||
application. If your application relies heavily on CRUD-alike interactions and/or `PATCH`
|
||||
restful operations, you should look at alternatives such as [JMSSerializer](https://github.com/schmittjoh/serializer).
|
||||
|
||||
## Extending `EntityManager` is deprecated
|
||||
|
||||
Final keyword will be added to the `EntityManager::class` in Doctrine ORM 3.0 in order to ensure that EntityManager
|
||||
is not used as valid extension point. Valid extension point should be EntityManagerInterface.
|
||||
|
||||
## Deprecated `EntityManager#clear($entityName)`
|
||||
|
||||
If your code relies on clearing a single entity type via `EntityManager#clear($entityName)`,
|
||||
the signature has been changed to `EntityManager#clear()`.
|
||||
|
||||
The main reason is that partial clears caused multiple issues with data integrity
|
||||
in the managed entity graph, which was constantly spawning more edge-case bugs/scenarios.
|
||||
|
||||
## Deprecated `EntityManager#flush($entity)` and `EntityManager#flush($entities)`
|
||||
|
||||
If your code relies on single entity flushing optimisations via
|
||||
`EntityManager#flush($entity)`, the signature has been changed to
|
||||
`EntityManager#flush()`.
|
||||
|
||||
Said API was affected by multiple data integrity bugs due to the fact
|
||||
that change tracking was being restricted upon a subset of the managed
|
||||
entities. The ORM cannot support committing subsets of the managed
|
||||
entities while also guaranteeing data integrity, therefore this
|
||||
utility was removed.
|
||||
|
||||
The `flush()` semantics will remain the same, but the change tracking will be performed
|
||||
on all entities managed by the unit of work, and not just on the provided
|
||||
`$entity` or `$entities`, as the parameter is now completely ignored.
|
||||
|
||||
The same applies to `UnitOfWork#commit($entity)`, which will simply be
|
||||
`UnitOfWork#commit()`.
|
||||
|
||||
If you would still like to perform batching operations over small `UnitOfWork`
|
||||
instances, it is suggested to follow these paths instead:
|
||||
|
||||
* eagerly use `EntityManager#clear()` in conjunction with a specific second level
|
||||
cache configuration (see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second-level-cache.html)
|
||||
* use an explicit change tracking policy (see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/change-tracking-policies.html)
|
||||
|
||||
## Deprecated `YAML` mapping drivers.
|
||||
|
||||
If your code relies on `YamlDriver` or `SimpleYamlDriver`, you **MUST** change to
|
||||
annotation or XML drivers instead.
|
||||
|
||||
## Deprecated: `Doctrine\ORM\EntityManagerInterface#copy()`
|
||||
|
||||
Method `Doctrine\ORM\EntityManagerInterface#copy()` never got its implementation and is deprecated.
|
||||
It will be removed in 3.0.
|
||||
|
||||
# Upgrade to 2.6
|
||||
|
||||
## Added `Doctrine\ORM\EntityRepository::count()` method
|
||||
@@ -297,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
|
||||
|
||||
@@ -396,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
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Version class and file
|
||||
project.version_class = Doctrine\\ORM\\Version
|
||||
project.version_file = lib/Doctrine/ORM/Version.php
|
||||
@@ -1,16 +0,0 @@
|
||||
version=2.0.0BETA2
|
||||
dependencies.common=2.0.0BETA4
|
||||
dependencies.dbal=2.0.0BETA4
|
||||
stability=beta
|
||||
build.dir=build
|
||||
dist.dir=dist
|
||||
report.dir=reports
|
||||
log.archive.dir=logs
|
||||
project.pirum_dir=
|
||||
project.download_dir=
|
||||
project.xsd_dir=
|
||||
test.phpunit_configuration_file=
|
||||
test.phpunit_generate_coverage=0
|
||||
test.pmd_reports=0
|
||||
test.pdepend_exec=
|
||||
test.phpmd_exec=
|
||||
101
build.xml
101
build.xml
@@ -1,101 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<project name="DoctrineORM" default="build" basedir=".">
|
||||
<property file="build.properties" />
|
||||
|
||||
<target name="php">
|
||||
<exec executable="which" outputproperty="php_executable">
|
||||
<arg value="php" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="prepare">
|
||||
<mkdir dir="build" />
|
||||
</target>
|
||||
|
||||
<target name="build" depends="check-git-checkout-clean,prepare,php,composer">
|
||||
<exec executable="${php_executable}">
|
||||
<arg value="build/composer.phar" />
|
||||
<arg value="archive" />
|
||||
<arg value="--dir=build" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="composer" depends="php,composer-check,composer-download">
|
||||
<exec executable="${php_executable}">
|
||||
<arg value="build/composer.phar" />
|
||||
<arg value="install" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="composer-check" depends="prepare">
|
||||
<available file="build/composer.phar" property="composer.present"/>
|
||||
</target>
|
||||
|
||||
<target name="composer-download" unless="composer.present">
|
||||
<exec executable="wget">
|
||||
<arg value="-Obuild/composer.phar" />
|
||||
<arg value="http://getcomposer.org/composer.phar" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="make-release" depends="check-git-checkout-clean,prepare,php">
|
||||
<replace file="${project.version_file}" token="-DEV" value="" failOnNoReplacements="true" />
|
||||
<exec executable="${php_executable}" outputproperty="doctrine.current_version" failonerror="true">
|
||||
<arg value="-r" />
|
||||
<arg value="require_once '${project.version_file}';echo ${project.version_class}::VERSION;" />
|
||||
</exec>
|
||||
<exec executable="${php_executable}" outputproperty="doctrine.next_version" failonerror="true">
|
||||
<arg value="-r" />
|
||||
<arg value="$parts = explode('.', str_ireplace(array('-DEV', '-ALPHA', '-BETA'), '', '${doctrine.current_version}'));
|
||||
if (count($parts) != 3) {
|
||||
throw new \InvalidArgumentException('Version is assumed in format x.y.z, ${doctrine.current_version} given');
|
||||
}
|
||||
$parts[2]++;
|
||||
echo implode('.', $parts);
|
||||
" />
|
||||
</exec>
|
||||
|
||||
<git-commit file="${project.version_file}" message="Release ${doctrine.current_version}" />
|
||||
<git-tag version="${doctrine.current_version}" />
|
||||
<replace file="${project.version_file}" token="${doctrine.current_version}" value="${doctrine.next_version}-DEV" />
|
||||
<git-commit file="${project.version_file}" message="Bump version to ${doctrine.next_version}" />
|
||||
</target>
|
||||
|
||||
<target name="check-git-checkout-clean">
|
||||
<exec executable="git" failonerror="true">
|
||||
<arg value="diff-index" />
|
||||
<arg value="--quiet" />
|
||||
<arg value="HEAD" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<macrodef name="git-commit">
|
||||
<attribute name="file" default="NOT SET"/>
|
||||
<attribute name="message" default="NOT SET"/>
|
||||
|
||||
<sequential>
|
||||
<exec executable="git">
|
||||
<arg value="add" />
|
||||
<arg value="@{file}" />
|
||||
</exec>
|
||||
<exec executable="git">
|
||||
<arg value="commit" />
|
||||
<arg value="-m" />
|
||||
<arg value="@{message}" />
|
||||
</exec>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<macrodef name="git-tag">
|
||||
<attribute name="version" default="NOT SET" />
|
||||
|
||||
<sequential>
|
||||
<exec executable="git">
|
||||
<arg value="tag" />
|
||||
<arg value="-m" />
|
||||
<arg value="v@{version}" />
|
||||
<arg value="v@{version}" />
|
||||
</exec>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</project>
|
||||
@@ -3,7 +3,7 @@
|
||||
"type": "library",
|
||||
"description": "Object-Relational-Mapper for PHP",
|
||||
"keywords": ["orm", "database"],
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"homepage": "https://www.doctrine-project.org/projects/orm.html",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
|
||||
@@ -13,23 +13,33 @@
|
||||
{"name": "Marco Pivetta", "email": "ocramius@gmail.com"}
|
||||
],
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.1.3"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1",
|
||||
"ext-pdo": "*",
|
||||
"doctrine/annotations": "~1.5",
|
||||
"doctrine/cache": "~1.6",
|
||||
"doctrine/collections": "^1.4",
|
||||
"doctrine/common": "^2.7.1",
|
||||
"doctrine/dbal": "^2.6",
|
||||
"doctrine/instantiator": "~1.1",
|
||||
"symfony/console": "~3.0|~4.0"
|
||||
"composer/package-versions-deprecated": "^1.8",
|
||||
"doctrine/annotations": "^1.8",
|
||||
"doctrine/cache": "^1.9.1",
|
||||
"doctrine/collections": "^1.5",
|
||||
"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/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"
|
||||
"symfony/yaml": "^3.4|^4.0|^5.0",
|
||||
"vimeo/psalm": "^3.11"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
|
||||
@@ -46,7 +56,7 @@
|
||||
"bin": ["bin/doctrine"],
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.6.x-dev"
|
||||
"dev-master": "2.7.x-dev"
|
||||
}
|
||||
},
|
||||
"archive": {
|
||||
|
||||
1348
composer.lock
generated
1348
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -249,7 +249,7 @@ Example usage
|
||||
$em->clear();
|
||||
|
||||
// Fetch the Location object
|
||||
$query = $em->createQuery("SELECT l FROM Geo\Entity\Location WHERE l.address = '1600 Amphitheatre Parkway, Mountain View, CA'");
|
||||
$query = $em->createQuery("SELECT l FROM Geo\Entity\Location l WHERE l.address = '1600 Amphitheatre Parkway, Mountain View, CA'");
|
||||
$location = $query->getSingleResult();
|
||||
|
||||
/* @var Geo\ValueObject\Point */
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ Serializing entity into the session
|
||||
-----------------------------------
|
||||
|
||||
Entities that are serialized into the session normally contain references to
|
||||
other entities as well. Think of the user entity has a reference to his
|
||||
other entities as well. Think of the user entity has a reference to their
|
||||
articles, groups, photos or many other different entities. If you serialize
|
||||
this object into the session then you don't want to serialize the related
|
||||
entities as well. This is why you should call ``EntityManager#detach()`` on this
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -25,8 +25,8 @@ the additional benefit of being able to re-use your validation in
|
||||
any other part of your domain.
|
||||
|
||||
Say we have an ``Order`` with several ``OrderLine`` instances. We
|
||||
never want to allow any customer to order for a larger sum than he
|
||||
is allowed to:
|
||||
never want to allow any customer to order for a larger sum than they
|
||||
are allowed to:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
|
||||
@@ -90,7 +90,10 @@ the UTC time at the time of the booking and the timezone the event happened in.
|
||||
|
||||
class UTCDateTimeType extends DateTimeType
|
||||
{
|
||||
static private $utc;
|
||||
/**
|
||||
* @var \DateTimeZone
|
||||
*/
|
||||
private static $utc;
|
||||
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -110,7 +113,7 @@ the UTC time at the time of the booking and the timezone the event happened in.
|
||||
$converted = \DateTime::createFromFormat(
|
||||
$platform->getDateTimeFormatString(),
|
||||
$value,
|
||||
self::$utc ? self::$utc : self::$utc = new \DateTimeZone('UTC')
|
||||
self::getUtc()
|
||||
);
|
||||
|
||||
if (! $converted) {
|
||||
@@ -123,6 +126,11 @@ the UTC time at the time of the booking and the timezone the event happened in.
|
||||
|
||||
return $converted;
|
||||
}
|
||||
|
||||
private static function getUtc(): \DateTimeZone
|
||||
{
|
||||
return self::$utc ?: self::$utc = new \DateTimeZone('UTC');
|
||||
}
|
||||
}
|
||||
|
||||
This database type makes sure that every DateTime instance is always saved in UTC, relative
|
||||
|
||||
@@ -99,7 +99,7 @@ Optional attributes:
|
||||
|
||||
- **length**: Used by the "string" type to determine its maximum
|
||||
length in the database. Doctrine does not validate the length of a
|
||||
string values for you.
|
||||
string value for you.
|
||||
|
||||
- **precision**: The precision for a decimal (exact numeric) column
|
||||
(applies only for decimal column), which is the maximum number of
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -286,7 +286,7 @@ below.
|
||||
// ...
|
||||
|
||||
/**
|
||||
* One Student has One Student.
|
||||
* One Student has One Mentor.
|
||||
* @OneToOne(targetEntity="Student")
|
||||
* @JoinColumn(name="mentor_id", referencedColumnName="id")
|
||||
*/
|
||||
|
||||
@@ -328,8 +328,8 @@ annotation.
|
||||
|
||||
In most cases using the automatic generator strategy (``@GeneratedValue``) is
|
||||
what you want. It defaults to the identifier generation mechanism your current
|
||||
database vendor prefers: AUTO_INCREMENT with MySQL, SERIAL with PostgreSQL,
|
||||
Sequences with Oracle and so on.
|
||||
database vendor prefers: AUTO_INCREMENT with MySQL, sequences with PostgreSQL
|
||||
and Oracle and so on.
|
||||
|
||||
Identifier Generation Strategies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -16,6 +16,15 @@ especially what the strategies presented here provide help with.
|
||||
operations.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Having an SQL logger enabled when processing batches can have a serious impact on performance and resource usage.
|
||||
To avoid that you should disable it in the DBAL configuration:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$em->getConnection()->getConfiguration()->setSQLLogger(null);
|
||||
|
||||
Bulk Inserts
|
||||
------------
|
||||
|
||||
@@ -75,7 +84,7 @@ with the batching strategy that was already used for bulk inserts:
|
||||
|
||||
<?php
|
||||
$batchSize = 20;
|
||||
$i = 0;
|
||||
$i = 1;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
$iterableResult = $q->iterate();
|
||||
foreach ($iterableResult as $row) {
|
||||
@@ -136,7 +145,7 @@ The following example shows how to do this:
|
||||
|
||||
<?php
|
||||
$batchSize = 20;
|
||||
$i = 0;
|
||||
$i = 1;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
$iterableResult = $q->iterate();
|
||||
while (($row = $iterableResult->next()) !== false) {
|
||||
|
||||
@@ -45,41 +45,29 @@ This documentation does not cover every single cache driver included
|
||||
with Doctrine. For an up-to-date-list, see the
|
||||
`cache directory on GitHub <https://github.com/doctrine/cache/tree/master/lib/Doctrine/Common/Cache>`_.
|
||||
|
||||
APC
|
||||
~~~
|
||||
PhpFileCache
|
||||
~~~~~~~~~~~~
|
||||
|
||||
In order to use the APC cache driver you must have it compiled and
|
||||
enabled in your php.ini. You can read about APC
|
||||
`in the PHP Documentation <http://us2.php.net/apc>`_. It will give
|
||||
you a little background information about what it is and how you
|
||||
can use it as well as how to install it.
|
||||
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.
|
||||
|
||||
Below is a simple example of how you could use the APC cache driver
|
||||
by itself.
|
||||
In order to use the ``PhpFileCache`` driver it must be able to write to
|
||||
a directory.
|
||||
|
||||
Below is an example of how to use the ``PhpFileCache`` driver by itself.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\ApcCache();
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
APCu
|
||||
~~~~
|
||||
|
||||
In order to use the APCu cache driver you must have it compiled and
|
||||
enabled in your php.ini. You can read about APCu
|
||||
`in the PHP Documentation <http://us2.php.net/apcu>`_. It will give
|
||||
you a little background information about what it is and how you
|
||||
can use it as well as how to install it.
|
||||
|
||||
Below is a simple example of how you could use the APCu cache driver
|
||||
by itself.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\ApcuCache();
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
The PhpFileCache is not distributed across multiple machines if you are running
|
||||
your application in a distributed setup. This is ok for the metadata and query
|
||||
cache but is not a good approach for the result cache.
|
||||
|
||||
Memcache
|
||||
~~~~~~~~
|
||||
@@ -128,24 +116,6 @@ driver by itself.
|
||||
$cacheDriver->setMemcached($memcached);
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
Xcache
|
||||
~~~~~~
|
||||
|
||||
In order to use the Xcache cache driver you must have it compiled
|
||||
and enabled in your php.ini. You can read about Xcache
|
||||
`here <http://xcache.lighttpd.net/>`_. It will give you a little
|
||||
background information about what it is and how you can use it as
|
||||
well as how to install it.
|
||||
|
||||
Below is a simple example of how you could use the Xcache cache
|
||||
driver by itself.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\XcacheCache();
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
Redis
|
||||
~~~~~
|
||||
|
||||
@@ -306,8 +276,11 @@ use on your ORM configuration.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$config->setQueryCacheImpl(new \Doctrine\Common\Cache\ApcuCache());
|
||||
$config->setQueryCacheImpl($cacheDriver);
|
||||
|
||||
Result Cache
|
||||
~~~~~~~~~~~~
|
||||
@@ -320,7 +293,11 @@ cache implementation.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$config->setResultCacheImpl(new \Doctrine\Common\Cache\ApcuCache());
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$config->setResultCacheImpl($cacheDriver);
|
||||
|
||||
Now when you're executing DQL queries you can configure them to use
|
||||
the result cache.
|
||||
@@ -337,7 +314,11 @@ result cache driver.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query->setResultCacheDriver(new \Doctrine\Common\Cache\ApcuCache());
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$query->setResultCacheDriver($cacheDriver);
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -389,7 +370,11 @@ first.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ApcuCache());
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$config->setMetadataCacheImpl($cacheDriver);
|
||||
|
||||
Now the metadata information will only be parsed once and stored in
|
||||
the cache driver.
|
||||
@@ -425,6 +410,12 @@ To clear the result cache use the ``orm:clear-cache:result`` task.
|
||||
All these tasks accept a ``--flush`` option to flush the entire
|
||||
contents of the cache instead of invalidating the entries.
|
||||
|
||||
.. note::
|
||||
|
||||
None of these tasks will work with APC, APCu, or XCache drivers
|
||||
because the memory that the cache is stored in is only accessible
|
||||
to the webserver.
|
||||
|
||||
Cache Chaining
|
||||
--------------
|
||||
|
||||
|
||||
@@ -71,8 +71,8 @@ follows:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\Common\NotifyPropertyChanged,
|
||||
Doctrine\Common\PropertyChangedListener;
|
||||
use Doctrine\Persistence\NotifyPropertyChanged,
|
||||
Doctrine\Persistence\PropertyChangedListener;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
|
||||
@@ -250,7 +250,7 @@ Retrieve the Username and Name of a CmsUser:
|
||||
$users = $query->getResult(); // array of CmsUser username and name values
|
||||
echo $users[0]['username'];
|
||||
|
||||
Retrieve a ForumUser and his single associated entity:
|
||||
Retrieve a ForumUser and its single associated entity:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -259,7 +259,7 @@ Retrieve a ForumUser and his single associated entity:
|
||||
$users = $query->getResult(); // array of ForumUser objects with the avatar association loaded
|
||||
echo get_class($users[0]->getAvatar());
|
||||
|
||||
Retrieve a CmsUser and fetch join all the phonenumbers he has:
|
||||
Retrieve a CmsUser and fetch join all the phonenumbers it has:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -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
|
||||
@@ -996,8 +996,9 @@ the Query class. Here they are:
|
||||
result contains more than one object, an ``NonUniqueResultException``
|
||||
is thrown. If the result contains no objects, an ``NoResultException``
|
||||
is thrown. The pure/mixed distinction does not apply.
|
||||
- ``Query#getOneOrNullResult()``: Retrieve a single object. If no
|
||||
object is found null will be returned.
|
||||
- ``Query#getOneOrNullResult()``: Retrieve a single object. If the
|
||||
result contains more than one object, a ``NonUniqueResultException``
|
||||
is thrown. If no object is found null will be returned.
|
||||
- ``Query#getArrayResult()``: Retrieves an array graph (a nested
|
||||
array) that is largely interchangeable with the object graph
|
||||
generated by ``Query#getResult()`` for read-only purposes.
|
||||
|
||||
@@ -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.
|
||||
@@ -243,6 +247,11 @@ a relevant lifecycle event. More than one callback can be defined for each
|
||||
lifecycle event. Lifecycle Callbacks are best used for simple operations
|
||||
specific to a particular entity class's lifecycle.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Note that Licecycle Callbacks are not supported for Embeddables.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
@@ -405,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
|
||||
@@ -418,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
|
||||
{
|
||||
@@ -440,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
|
||||
{
|
||||
@@ -496,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
|
||||
~~~~~~~~~~
|
||||
@@ -581,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
|
||||
@@ -730,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.
|
||||
|
||||
@@ -986,4 +995,3 @@ process and manipulate the instance.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -198,6 +198,21 @@ No, it is not supported to sort by function in DQL. If you need this functionali
|
||||
use a native-query or come up with another solution. As a side note: Sorting with ORDER BY RAND() is painfully slow
|
||||
starting with 1000 rows.
|
||||
|
||||
Is it better to write DQL or to generate it with the query builder?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The purpose of the ``QueryBuilder`` is to generate DQL dynamically,
|
||||
which is useful when you have optional filters, conditional joins, etc.
|
||||
|
||||
But the ``QueryBuilder`` is not an alternative to DQL, it actually generates DQL
|
||||
queries at runtime, which are then interpreted by Doctrine. This means that
|
||||
using the ``QueryBuilder`` to build and run a query is actually always slower
|
||||
than only running the corresponding DQL query.
|
||||
|
||||
So if you only need to generate a query and bind parameters to it,
|
||||
you should use plain DQL, as this is a simpler and much more readable solution.
|
||||
You should only use the ``QueryBuilder`` when you can't achieve what you want to do with a DQL query.
|
||||
|
||||
A Query fails, how can I debug it?
|
||||
----------------------------------
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ proper quoting of parameters.
|
||||
|
||||
<?php
|
||||
namespace Example;
|
||||
use Doctrine\ORM\Mapping\ClassMetaData,
|
||||
use Doctrine\ORM\Mapping\ClassMetadata,
|
||||
Doctrine\ORM\Query\Filter\SQLFilter;
|
||||
|
||||
class MyLocaleFilter extends SQLFilter
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
--------------
|
||||
|
||||
@@ -4,9 +4,13 @@ Implementing a NamingStrategy
|
||||
.. versionadded:: 2.3
|
||||
|
||||
Using a naming strategy you can provide rules for generating database identifiers,
|
||||
column or table names when the column or table name is not given. This feature helps
|
||||
column or table names. This feature helps
|
||||
reduce the verbosity of the mapping document, eliminating repetitive noise (eg: ``TABLE_``).
|
||||
|
||||
.. warning
|
||||
|
||||
The naming strategy is always overridden by entity mapping such as the `Table` annotation.
|
||||
|
||||
Configuring a naming strategy
|
||||
-----------------------------
|
||||
The default strategy used by Doctrine is quite minimal.
|
||||
|
||||
@@ -9,6 +9,12 @@ programmatically build queries, and also provides a fluent API.
|
||||
This means that you can change between one methodology to the other
|
||||
as you want, or just pick a preferred one.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``QueryBuilder`` is not an abstraction of DQL, but merely a tool to dynamically build it.
|
||||
You should still use plain DQL when you can, as it is simpler and more readable.
|
||||
More about this in the :doc:`FAQ <faq>`_.
|
||||
|
||||
Constructing a new QueryBuilder object
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -80,7 +86,7 @@ Working with QueryBuilder
|
||||
High level API methods
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To simplify even more the way you build a query in Doctrine, you can take
|
||||
The most straightforward way to build a dynamic query with the ``QueryBuilder`` is by taking
|
||||
advantage of Helper methods. For all base code, there is a set of
|
||||
useful methods to simplify a programmer's life. To illustrate how
|
||||
to work with them, here is the same example 6 re-written using
|
||||
@@ -97,10 +103,9 @@ to work with them, here is the same example 6 re-written using
|
||||
->orderBy('u.name', 'ASC');
|
||||
|
||||
``QueryBuilder`` helper methods are considered the standard way to
|
||||
build DQL queries. Although it is supported, using string-based
|
||||
queries should be avoided. You are greatly encouraged to use
|
||||
``$qb->expr()->*`` methods. Here is a converted example 8 to
|
||||
suggested standard way to build queries:
|
||||
use the ``QueryBuilder``. The ``$qb->expr()->*`` methods can help you
|
||||
build conditional expressions dynamically. Here is a converted example 8 to
|
||||
suggested way to build queries with dynamic conditions:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -250,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:
|
||||
@@ -576,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'));
|
||||
|
||||
|
||||
@@ -252,15 +252,6 @@ will output the SQL for the ran operation.
|
||||
Before using the orm:schema-tool commands, remember to configure
|
||||
your cli-config.php properly.
|
||||
|
||||
.. note::
|
||||
|
||||
When using the Annotation Mapping Driver you have to either setup
|
||||
your autoloader in the cli-config.php correctly to find all the
|
||||
entities, or you can use the second argument of the
|
||||
``EntityManagerHelper`` to specify all the paths of your entities
|
||||
(or mapping files), i.e.
|
||||
``new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em, $mappingPaths);``
|
||||
|
||||
Entity Generation
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ side of the association and these 2 references both represent the
|
||||
same association but can change independently of one another. Of
|
||||
course, in a correct application the semantics of the bidirectional
|
||||
association are properly maintained by the application developer
|
||||
(that's his responsibility). Doctrine needs to know which of these
|
||||
(that's their responsibility). Doctrine needs to know which of these
|
||||
two in-memory references is the one that should be persisted and
|
||||
which not. This is what the owning/inverse concept is mainly used
|
||||
for.
|
||||
|
||||
@@ -148,15 +148,15 @@ Hydration
|
||||
~~~~~~~~~
|
||||
|
||||
Responsible for creating a final result from a raw database statement and a
|
||||
result-set mapping object. The developer can choose which kind of result he
|
||||
wishes to be hydrated. Default result-types include:
|
||||
result-set mapping object. The developer can choose which kind of result they
|
||||
wish to be hydrated. Default result-types include:
|
||||
|
||||
- SQL to Entities
|
||||
- SQL to structured Arrays
|
||||
- SQL to simple scalar result arrays
|
||||
- SQL to a single result variable
|
||||
|
||||
Hydration to entities and arrays is one of most complex parts of Doctrine
|
||||
Hydration to entities and arrays is one of the most complex parts of Doctrine
|
||||
algorithm-wise. It can build results with for example:
|
||||
|
||||
- Single table selects
|
||||
|
||||
@@ -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
|
||||
------------------
|
||||
|
||||
@@ -800,7 +813,9 @@ DQL and its syntax as well as the Doctrine class can be found in
|
||||
:doc:`the dedicated chapter <dql-doctrine-query-language>`.
|
||||
For programmatically building up queries based on conditions that
|
||||
are only known at runtime, Doctrine provides the special
|
||||
``Doctrine\ORM\QueryBuilder`` class. More information on
|
||||
``Doctrine\ORM\QueryBuilder`` class. While this a powerful tool,
|
||||
it also brings more complexity to your code compared to plain DQL,
|
||||
so you should only use it when you need it. More information on
|
||||
constructing queries with a QueryBuilder can be found
|
||||
:doc:`in Query Builder chapter <query-builder>`.
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -35,6 +35,15 @@ With extra lazy collections you can now not only add entities to large collectio
|
||||
easily using a combination of ``count`` and ``slice``.
|
||||
|
||||
|
||||
.. warning::
|
||||
|
||||
``removeElement`` directly issued DELETE queries to the database from
|
||||
version 2.4.0 to 2.7.0. This circumvents the flush operation and might run
|
||||
outside a transactional boundary if you don't create one yourself. We
|
||||
consider this a critical bug in the assumptio of how the ORM works and
|
||||
reverted ``removeElement`` EXTRA_LAZY behavior in 2.7.1.
|
||||
|
||||
|
||||
Enabling Extra-Lazy Associations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ requirements:
|
||||
- Bug reporters and engineers are both Users of the system.
|
||||
- A User can create new Bugs.
|
||||
- The assigned engineer can close a Bug.
|
||||
- A User can see all his reported or assigned Bugs.
|
||||
- A User can see all their reported or assigned Bugs.
|
||||
- Bugs can be paginated through a list-view.
|
||||
|
||||
Project Setup
|
||||
@@ -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
|
||||
@@ -1210,8 +1209,7 @@ The console output of this script is then:
|
||||
throw your ORM into the dumpster, because it doesn't support some
|
||||
the more powerful SQL concepts.
|
||||
|
||||
|
||||
Instead of handwriting DQL you can use the ``QueryBuilder`` retrieved
|
||||
If you need to build your query dynamically, you can use the ``QueryBuilder`` retrieved
|
||||
by calling ``$entityManager->createQueryBuilder()``. There are more
|
||||
details about this in the relevant part of the documentation.
|
||||
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -583,21 +590,45 @@ abstract class AbstractQuery
|
||||
* Set whether or not to cache the results of this query and if so, for
|
||||
* how long and which ID to use for the cache entry.
|
||||
*
|
||||
* @param boolean $bool
|
||||
* @param integer $lifetime
|
||||
* @param string $resultCacheId
|
||||
* @deprecated 2.7 Use {@see enableResultCache} and {@see disableResultCache} instead.
|
||||
*
|
||||
* @param bool $useCache
|
||||
* @param int $lifetime
|
||||
* @param string $resultCacheId
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function useResultCache($bool, $lifetime = null, $resultCacheId = null)
|
||||
public function useResultCache($useCache, $lifetime = null, $resultCacheId = null)
|
||||
{
|
||||
if ($bool) {
|
||||
$this->setResultCacheLifetime($lifetime);
|
||||
$this->setResultCacheId($resultCacheId);
|
||||
return $useCache
|
||||
? $this->enableResultCache($lifetime, $resultCacheId)
|
||||
: $this->disableResultCache();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Enables caching of the results of this query, for given or default amount of seconds
|
||||
* and optionally specifies which ID to use for the cache entry.
|
||||
*
|
||||
* @param int|null $lifetime How long the cache entry is valid, in seconds.
|
||||
* @param string|null $resultCacheId ID to use for the cache entry.
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function enableResultCache(?int $lifetime = null, ?string $resultCacheId = null) : self
|
||||
{
|
||||
$this->setResultCacheLifetime($lifetime);
|
||||
$this->setResultCacheId($resultCacheId);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables caching of the results of this query.
|
||||
*
|
||||
* @return static This query instance.
|
||||
*/
|
||||
public function disableResultCache() : self
|
||||
{
|
||||
$this->_queryCacheProfile = null;
|
||||
|
||||
return $this;
|
||||
@@ -606,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.
|
||||
*/
|
||||
@@ -822,8 +853,9 @@ abstract class AbstractQuery
|
||||
*
|
||||
* Alias for getSingleResult(HYDRATE_SINGLE_SCALAR).
|
||||
*
|
||||
* @return mixed The scalar result, or NULL if the query returned no result.
|
||||
* @return mixed The scalar result.
|
||||
*
|
||||
* @throws NoResultException If the query returned no result.
|
||||
* @throws NonUniqueResultException If the query result is not unique.
|
||||
*/
|
||||
public function getSingleScalarResult()
|
||||
@@ -940,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();
|
||||
@@ -957,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());
|
||||
@@ -1044,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()
|
||||
{
|
||||
|
||||
@@ -60,9 +60,6 @@ class DefaultCache implements Cache
|
||||
*/
|
||||
private $defaultQueryCache;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
|
||||
@@ -260,7 +260,7 @@ class DefaultQueryCache implements QueryCache
|
||||
throw new CacheException("Second-level cache query supports only select statements.");
|
||||
}
|
||||
|
||||
if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD]) && $hints[Query::HINT_FORCE_PARTIAL_LOAD]) {
|
||||
if (($hints[Query\SqlWalker::HINT_PARTIAL] ?? false) === true || ($hints[Query::HINT_FORCE_PARTIAL_LOAD] ?? false) === true) {
|
||||
throw new CacheException("Second level cache does not support partial entities.");
|
||||
}
|
||||
|
||||
@@ -279,9 +279,12 @@ class DefaultQueryCache implements QueryCache
|
||||
|
||||
$region = $persister->getCacheRegion();
|
||||
|
||||
$cm = $this->em->getClassMetadata($entityName);
|
||||
assert($cm instanceof ClassMetadata);
|
||||
|
||||
foreach ($result as $index => $entity) {
|
||||
$identifier = $this->uow->getEntityIdentifier($entity);
|
||||
$entityKey = new EntityCacheKey($entityName, $identifier);
|
||||
$identifier = $this->uow->getEntityIdentifier($entity);
|
||||
$entityKey = new EntityCacheKey($cm->rootEntityName, $identifier);
|
||||
|
||||
if (($key->cacheMode & Cache::MODE_REFRESH) || ! $region->contains($entityKey)) {
|
||||
// Cancel put result if entity put fail
|
||||
@@ -345,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)
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -243,20 +243,6 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
return $this->persister->get($collection, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeElement(PersistentCollection $collection, $element)
|
||||
{
|
||||
if ($persisterResult = $this->persister->removeElement($collection, $element)) {
|
||||
$this->evictCollectionCache($collection);
|
||||
$this->evictElementCache($this->sourceEntity->rootEntityName, $collection->getOwner());
|
||||
$this->evictElementCache($this->targetEntity->rootEntityName, $element);
|
||||
}
|
||||
|
||||
return $persisterResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -249,6 +249,8 @@ class FileLockRegion implements ConcurrentRegion
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function unlock(CacheKey $key, Lock $lock)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
@@ -70,6 +71,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* Gets the directory where Doctrine generates any necessary proxy class files.
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @deprecated 2.7 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer
|
||||
* @see https://github.com/Ocramius/ProxyManager
|
||||
*/
|
||||
public function getProxyDir()
|
||||
{
|
||||
@@ -82,6 +86,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* Gets the strategy for automatically generating proxy classes.
|
||||
*
|
||||
* @return int Possible values are constants of Doctrine\Common\Proxy\AbstractProxyFactory.
|
||||
*
|
||||
* @deprecated 2.7 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer
|
||||
* @see https://github.com/Ocramius/ProxyManager
|
||||
*/
|
||||
public function getAutoGenerateProxyClasses()
|
||||
{
|
||||
@@ -107,6 +114,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* Gets the namespace where proxy classes reside.
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @deprecated 2.7 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer
|
||||
* @see https://github.com/Ocramius/ProxyManager
|
||||
*/
|
||||
public function getProxyNamespace()
|
||||
{
|
||||
@@ -432,6 +442,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|null
|
||||
* @psalm-return ?class-string
|
||||
*/
|
||||
public function getCustomStringFunction($name)
|
||||
{
|
||||
@@ -484,6 +495,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|null
|
||||
* @psalm-return ?class-string
|
||||
*/
|
||||
public function getCustomNumericFunction($name)
|
||||
{
|
||||
@@ -524,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)
|
||||
{
|
||||
@@ -536,6 +550,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* @psalm-return ?class-string $name
|
||||
*/
|
||||
public function getCustomDatetimeFunction($name)
|
||||
{
|
||||
@@ -557,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)
|
||||
{
|
||||
@@ -587,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)
|
||||
{
|
||||
@@ -614,6 +634,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* @param string $cmfName
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param class-string $cmfName
|
||||
*/
|
||||
public function setClassMetadataFactoryName($cmfName)
|
||||
{
|
||||
@@ -622,6 +644,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @psalm-return class-string
|
||||
*/
|
||||
public function getClassMetadataFactoryName()
|
||||
{
|
||||
@@ -648,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)
|
||||
{
|
||||
@@ -667,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)
|
||||
{
|
||||
@@ -686,6 +712,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* @since 2.2
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @psalm-return class-string
|
||||
*/
|
||||
public function getDefaultRepositoryClassName()
|
||||
{
|
||||
@@ -909,3 +937,5 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
$this->_attributes['defaultQueryHints'][$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(MappingDriver::class);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,12 @@ 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;
|
||||
|
||||
/**
|
||||
* The EntityManager is the central access point to ORM functionality.
|
||||
@@ -323,7 +328,7 @@ use Throwable;
|
||||
*/
|
||||
public function createNamedNativeQuery($name)
|
||||
{
|
||||
list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
|
||||
[$sql, $rsm] = $this->config->getNamedNativeQuery($name);
|
||||
|
||||
return $this->createNativeQuery($sql, $rsm);
|
||||
}
|
||||
@@ -354,6 +359,13 @@ use Throwable;
|
||||
*/
|
||||
public function flush($entity = null)
|
||||
{
|
||||
if ($entity !== null) {
|
||||
@trigger_error(
|
||||
'Calling ' . __METHOD__ . '() with any arguments to flush specific entities is deprecated and will not be supported in Doctrine ORM 3.0.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
}
|
||||
|
||||
$this->errorIfClosed();
|
||||
|
||||
$this->unitOfWork->commit($entity);
|
||||
@@ -362,7 +374,7 @@ use Throwable;
|
||||
/**
|
||||
* 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
|
||||
@@ -377,9 +389,9 @@ use Throwable;
|
||||
* @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);
|
||||
@@ -537,9 +549,9 @@ use Throwable;
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
@@ -547,6 +559,13 @@ use Throwable;
|
||||
throw ORMInvalidArgumentException::invalidEntityName($entityName);
|
||||
}
|
||||
|
||||
if ($entityName !== null) {
|
||||
@trigger_error(
|
||||
'Calling ' . __METHOD__ . '() with any arguments to clear specific entities is deprecated and will not be supported in Doctrine ORM 3.0.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
}
|
||||
|
||||
$this->unitOfWork->clear(
|
||||
null === $entityName
|
||||
? null
|
||||
@@ -649,9 +668,13 @@ use Throwable;
|
||||
* @return void
|
||||
*
|
||||
* @throws ORMInvalidArgumentException
|
||||
*
|
||||
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
|
||||
*/
|
||||
public function detach($entity)
|
||||
{
|
||||
@trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
if ( ! is_object($entity)) {
|
||||
throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()', $entity);
|
||||
}
|
||||
@@ -670,9 +693,13 @@ use Throwable;
|
||||
*
|
||||
* @throws ORMInvalidArgumentException
|
||||
* @throws ORMException
|
||||
*
|
||||
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
|
||||
*/
|
||||
public function merge($entity)
|
||||
{
|
||||
@trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
if ( ! is_object($entity)) {
|
||||
throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()', $entity);
|
||||
}
|
||||
@@ -684,12 +711,11 @@ use Throwable;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @todo Implementation need. This is necessary since $e2 = clone $e1; throws an E_FATAL when access anything on $e:
|
||||
* Fatal error: Maximum function nesting level of '100' reached, aborting!
|
||||
*/
|
||||
public function copy($entity, $deep = false)
|
||||
{
|
||||
@trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0.', E_USER_DEPRECATED);
|
||||
|
||||
throw new \BadMethodCallException("Not implemented.");
|
||||
}
|
||||
|
||||
@@ -706,7 +732,7 @@ use Throwable;
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
|
||||
/**
|
||||
* EntityManager interface
|
||||
@@ -190,6 +190,8 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* Creates a copy of the given entity. Can create a shallow or a deep copy.
|
||||
*
|
||||
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @param object $entity The entity to copy.
|
||||
* @param boolean $deep FALSE for a shallow copy, TRUE for a deep copy.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -38,7 +38,7 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
private $entityClass;
|
||||
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker;
|
||||
use PDO;
|
||||
use function array_map;
|
||||
use function in_array;
|
||||
@@ -227,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.");
|
||||
}
|
||||
@@ -259,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)
|
||||
{
|
||||
@@ -351,13 +363,11 @@ abstract class AbstractHydrator
|
||||
|
||||
// WARNING: BC break! We know this is the desired behavior to type convert values, but this
|
||||
// erroneous behavior exists since 2.0 and we're forced to keep compatibility.
|
||||
if ( ! isset($cacheKeyInfo['isScalar'])) {
|
||||
$dqlAlias = $cacheKeyInfo['dqlAlias'];
|
||||
$type = $cacheKeyInfo['type'];
|
||||
$fieldName = $dqlAlias . '_' . $fieldName;
|
||||
$value = $type
|
||||
? $type->convertToPHPValue($value, $this->_platform)
|
||||
: $value;
|
||||
if (! isset($cacheKeyInfo['isScalar'])) {
|
||||
$type = $cacheKeyInfo['type'];
|
||||
$value = $type ? $type->convertToPHPValue($value, $this->_platform) : $value;
|
||||
|
||||
$fieldName = $cacheKeyInfo['dqlAlias'] . '_' . $fieldName;
|
||||
}
|
||||
|
||||
$rowData[$fieldName] = $value;
|
||||
@@ -422,6 +432,12 @@ abstract class AbstractHydrator
|
||||
'class' => new \ReflectionClass($mapping['className']),
|
||||
];
|
||||
|
||||
case isset($this->_rsm->scalarMappings[$key], $this->_hints[LimitSubqueryWalker::FORCE_DBAL_TYPE_CONVERSION]):
|
||||
return $this->_cache[$key] = [
|
||||
'fieldName' => $this->_rsm->scalarMappings[$key],
|
||||
'type' => Type::getType($this->_rsm->typeMappings[$key]),
|
||||
'dqlAlias' => '',
|
||||
];
|
||||
case (isset($this->_rsm->scalarMappings[$key])):
|
||||
return $this->_cache[$key] = [
|
||||
'isScalar' => true,
|
||||
|
||||
@@ -422,7 +422,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$this->resultPointers[$dqlAlias] = $reflFieldValue[$index];
|
||||
}
|
||||
} else if ( ! $reflFieldValue) {
|
||||
$reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
|
||||
$this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
|
||||
} else if ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
|
||||
$reflFieldValue->setInitialized(true);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ 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
|
||||
{
|
||||
@@ -76,10 +78,11 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function hydrateRowData(array $sqlResult, array &$result)
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
$entityName = $this->class->name;
|
||||
$data = [];
|
||||
$entityName = $this->class->name;
|
||||
$data = [];
|
||||
$discrColumnValue = null;
|
||||
|
||||
// We need to find the correct entity class name if we have inheritance in resultset
|
||||
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||
@@ -90,26 +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]];
|
||||
$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));
|
||||
@@ -134,6 +138,11 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
|
||||
// Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
|
||||
if ( ! isset($data[$fieldName]) || ! $valueIsNull) {
|
||||
// If we have inheritance in resultset, make sure the field belongs to the correct class
|
||||
if (isset($cacheKeyInfo['discriminatorValues']) && ! in_array((string) $discrColumnValue, $cacheKeyInfo['discriminatorValues'], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data[$fieldName] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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 = [])
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,7 +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
|
||||
@@ -56,7 +60,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
private $targetPlatform;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver
|
||||
* @var MappingDriver
|
||||
*/
|
||||
private $driver;
|
||||
|
||||
@@ -275,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
|
||||
@@ -401,10 +410,10 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass)
|
||||
{
|
||||
foreach ($parentClass->fieldMappings as $mapping) {
|
||||
if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$mapping['inherited'] = $parentClass->name;
|
||||
}
|
||||
if ( ! isset($mapping['declared'])) {
|
||||
if (! isset($mapping['declared'])) {
|
||||
$mapping['declared'] = $parentClass->name;
|
||||
}
|
||||
$subClass->addInheritedFieldMapping($mapping);
|
||||
@@ -795,3 +804,6 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
return $this->targetPlatform;
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadataInterface::class);
|
||||
interface_exists(ReflectionService::class);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -30,6 +30,8 @@ class DefaultEntityListenerResolver implements EntityListenerResolver
|
||||
{
|
||||
/**
|
||||
* @var array Map to store entity listener instances.
|
||||
*
|
||||
* @psalm-var array<class-string, object>
|
||||
*/
|
||||
private $instances = [];
|
||||
|
||||
|
||||
@@ -99,7 +99,8 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
$schema = '';
|
||||
|
||||
if (isset($association['joinTable']['schema'])) {
|
||||
$schema = $association['joinTable']['schema'] . '.';
|
||||
$schema = $association['joinTable']['schema'];
|
||||
$schema .= ! $platform->supportsSchemas() && $platform->canEmulateSchemas() ? '__' : '.';
|
||||
}
|
||||
|
||||
$tableName = $association['joinTable']['name'];
|
||||
|
||||
@@ -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,7 +40,8 @@ use Doctrine\ORM\Mapping\MappingException;
|
||||
class AnnotationDriver extends AbstractAnnotationDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @var int[]
|
||||
* @psalm-var array<class-string, int>
|
||||
*/
|
||||
protected $entityAnnotationClasses = [
|
||||
Mapping\Entity::class => 1,
|
||||
@@ -273,7 +275,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
|
||||
}
|
||||
|
||||
// Evaluate annotations on properties/fields
|
||||
/* @var $property \ReflectionProperty */
|
||||
foreach ($class->getProperties() as $property) {
|
||||
if ($metadata->isMappedSuperclass && ! $property->isPrivate()
|
||||
||
|
||||
@@ -504,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);
|
||||
@@ -524,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]);
|
||||
@@ -557,7 +556,7 @@ class AnnotationDriver extends AbstractAnnotationDriver
|
||||
*
|
||||
* @param \ReflectionMethod $method
|
||||
*
|
||||
* @return array
|
||||
* @return callable[]
|
||||
*/
|
||||
private function getMethodCallbacks(\ReflectionMethod $method)
|
||||
{
|
||||
@@ -605,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)
|
||||
{
|
||||
@@ -625,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)
|
||||
{
|
||||
@@ -671,3 +693,5 @@ class AnnotationDriver extends AbstractAnnotationDriver
|
||||
return new self($reader, $paths);
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -20,15 +20,18 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* The DatabaseDriver reverse engineers the mapping metadata from a database.
|
||||
@@ -386,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)
|
||||
{
|
||||
@@ -486,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)
|
||||
{
|
||||
@@ -500,7 +521,7 @@ class DatabaseDriver implements MappingDriver
|
||||
*
|
||||
* @param \Doctrine\DBAL\Schema\Table $table
|
||||
*
|
||||
* @return array
|
||||
* @return string[]
|
||||
*/
|
||||
private function getTablePrimaryKeys(Table $table)
|
||||
{
|
||||
@@ -548,9 +569,11 @@ class DatabaseDriver implements MappingDriver
|
||||
|
||||
// Replace _id if it is a foreignkey column
|
||||
if ($fk) {
|
||||
$columnName = str_replace('_id', '', $columnName);
|
||||
$columnName = preg_replace('/_id$/', '', $columnName);
|
||||
}
|
||||
|
||||
return Inflector::camelize($columnName);
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -19,12 +19,14 @@
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* The YamlDriver reads the mapping metadata from yaml schema files.
|
||||
@@ -34,6 +36,8 @@ use Symfony\Component\Yaml\Yaml;
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan H. Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*/
|
||||
class YamlDriver extends FileDriver
|
||||
{
|
||||
@@ -44,6 +48,11 @@ class YamlDriver extends FileDriver
|
||||
*/
|
||||
public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
|
||||
{
|
||||
@trigger_error(
|
||||
'YAML mapping driver is deprecated and will be removed in Doctrine ORM 3.0, please migrate to annotation or XML driver.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
|
||||
parent::__construct($locator, $fileExtension);
|
||||
}
|
||||
|
||||
@@ -675,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)
|
||||
{
|
||||
@@ -717,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)
|
||||
{
|
||||
@@ -778,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)
|
||||
{
|
||||
@@ -809,3 +845,5 @@ class YamlDriver extends FileDriver
|
||||
return Yaml::parse(file_get_contents($file));
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -20,30 +20,55 @@
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use const CASE_LOWER;
|
||||
use const CASE_UPPER;
|
||||
use const E_USER_DEPRECATED;
|
||||
use function preg_replace;
|
||||
use function strpos;
|
||||
use function strrpos;
|
||||
use function strtolower;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
use function trigger_error;
|
||||
|
||||
/**
|
||||
* Naming strategy implementing the underscore naming convention.
|
||||
* Converts 'MyEntity' to 'my_entity' or 'MY_ENTITY'.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.3
|
||||
* @author Fabio B. Silva <fabio.bat.silva@gmail.com>
|
||||
*/
|
||||
class UnderscoreNamingStrategy implements NamingStrategy
|
||||
{
|
||||
private const DEFAULT_PATTERN = '/(?<=[a-z])([A-Z])/';
|
||||
private const NUMBER_AWARE_PATTERN = '/(?<=[a-z0-9])([A-Z])/';
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $case;
|
||||
|
||||
/** @var string */
|
||||
private $pattern;
|
||||
|
||||
/**
|
||||
* Underscore naming strategy construct.
|
||||
*
|
||||
* @param integer $case CASE_LOWER | CASE_UPPER
|
||||
* @param int $case CASE_LOWER | CASE_UPPER
|
||||
*/
|
||||
public function __construct($case = CASE_LOWER)
|
||||
public function __construct($case = CASE_LOWER, bool $numberAware = false)
|
||||
{
|
||||
$this->case = $case;
|
||||
if (! $numberAware) {
|
||||
@trigger_error(
|
||||
'Creating ' . self::class . ' without making it number aware is deprecated and will be removed in Doctrine ORM 3.0.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
}
|
||||
|
||||
$this->case = $case;
|
||||
$this->pattern = $numberAware ? self::NUMBER_AWARE_PATTERN : self::DEFAULT_PATTERN;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +82,7 @@ class UnderscoreNamingStrategy implements NamingStrategy
|
||||
/**
|
||||
* Sets string case CASE_LOWER | CASE_UPPER.
|
||||
* Alphabetic characters converted to lowercase or uppercase.
|
||||
*
|
||||
*
|
||||
* @param integer $case
|
||||
*
|
||||
* @return void
|
||||
@@ -118,7 +143,7 @@ class UnderscoreNamingStrategy implements NamingStrategy
|
||||
{
|
||||
return $this->classToTableName($sourceEntity) . '_' . $this->classToTableName($targetEntity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -127,15 +152,10 @@ class UnderscoreNamingStrategy implements NamingStrategy
|
||||
return $this->classToTableName($entityName) . '_' .
|
||||
($referencedColumnName ?: $this->referenceColumnName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function underscore($string)
|
||||
|
||||
private function underscore(string $string) : string
|
||||
{
|
||||
$string = preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $string);
|
||||
$string = preg_replace($this->pattern, '_$1', $string);
|
||||
|
||||
if ($this->case === CASE_UPPER) {
|
||||
return strtoupper($string);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ class OptimisticLockException extends ORMException
|
||||
|
||||
/**
|
||||
* @param string $msg
|
||||
* @param object $entity
|
||||
* @param object|null $entity
|
||||
*/
|
||||
public function __construct($msg, $entity)
|
||||
{
|
||||
|
||||
@@ -25,7 +25,6 @@ use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Selectable;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use function array_merge;
|
||||
use function get_class;
|
||||
|
||||
/**
|
||||
@@ -338,6 +337,8 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function remove($key)
|
||||
{
|
||||
@@ -368,16 +369,6 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
|
||||
*/
|
||||
public function removeElement($element)
|
||||
{
|
||||
if ( ! $this->initialized && $this->association['fetch'] === ClassMetadata::FETCH_EXTRA_LAZY) {
|
||||
if ($this->collection->contains($element)) {
|
||||
return $this->collection->removeElement($element);
|
||||
}
|
||||
|
||||
$persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association);
|
||||
|
||||
return $persister->removeElement($this, $element);
|
||||
}
|
||||
|
||||
$removed = parent::removeElement($element);
|
||||
|
||||
if ( ! $removed) {
|
||||
@@ -521,6 +512,8 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
@@ -567,9 +560,7 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
|
||||
if ($this->association['isOwningSide'] && $this->owner) {
|
||||
$this->changed();
|
||||
|
||||
if (! $this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingDeferredExplicit()) {
|
||||
$uow->scheduleCollectionDeletion($this);
|
||||
}
|
||||
$uow->scheduleCollectionDeletion($this);
|
||||
|
||||
$this->takeSnapshot();
|
||||
}
|
||||
@@ -582,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'];
|
||||
}
|
||||
@@ -672,7 +665,7 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
|
||||
|
||||
$criteria = clone $criteria;
|
||||
$criteria->where($expression);
|
||||
$criteria->orderBy(array_merge($this->association['orderBy'] ?? [], $criteria->getOrderings()));
|
||||
$criteria->orderBy($criteria->getOrderings() ?: $this->association['orderBy'] ?? []);
|
||||
|
||||
$persister = $this->em->getUnitOfWork()->getEntityPersister($this->association['targetEntity']);
|
||||
|
||||
|
||||
@@ -90,16 +90,6 @@ interface CollectionPersister
|
||||
*/
|
||||
public function containsKey(PersistentCollection $collection, $key);
|
||||
|
||||
/**
|
||||
* Removes an element.
|
||||
*
|
||||
* @param \Doctrine\ORM\PersistentCollection $collection
|
||||
* @param object $element
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function removeElement(PersistentCollection $collection, $element);
|
||||
|
||||
/**
|
||||
* Gets an element by key.
|
||||
*
|
||||
|
||||
@@ -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,29 +208,17 @@ 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);
|
||||
|
||||
return (bool) $this->conn->fetchColumn($sql, $params, 0, $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function removeElement(PersistentCollection $collection, $element)
|
||||
{
|
||||
if ( ! $this->isValidEntityState($element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictions($collection, $element, false);
|
||||
|
||||
$sql = 'DELETE FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
|
||||
|
||||
return (bool) $this->conn->executeUpdate($sql, $params, $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -304,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)
|
||||
{
|
||||
@@ -351,7 +345,9 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
*
|
||||
* @param array $mapping
|
||||
*
|
||||
* @return array
|
||||
* @return string[]
|
||||
*
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
protected function getOnConditionSQL($mapping)
|
||||
{
|
||||
@@ -377,9 +373,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @override
|
||||
* @return string
|
||||
*/
|
||||
protected function getDeleteSQL(PersistentCollection $collection)
|
||||
{
|
||||
@@ -397,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)
|
||||
{
|
||||
@@ -432,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)
|
||||
{
|
||||
@@ -468,6 +463,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
* @param mixed $element
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @psalm-return list<mixed>
|
||||
*/
|
||||
protected function getDeleteRowSQLParameters(PersistentCollection $collection, $element)
|
||||
{
|
||||
@@ -481,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)
|
||||
{
|
||||
@@ -519,6 +518,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
* @param mixed $element
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @psalm-return list<mixed>
|
||||
*/
|
||||
protected function getInsertRowSQLParameters(PersistentCollection $collection, $element)
|
||||
{
|
||||
@@ -532,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)
|
||||
{
|
||||
@@ -580,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)
|
||||
{
|
||||
@@ -644,7 +649,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
}
|
||||
|
||||
if ($addFilters) {
|
||||
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
|
||||
[$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($filterMapping);
|
||||
|
||||
if ($filterSql) {
|
||||
$quotedJoinTable .= ' ' . $joinTargetEntitySQL;
|
||||
@@ -665,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)
|
||||
{
|
||||
@@ -710,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;
|
||||
@@ -741,7 +748,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
|
||||
$valueVisitor->dispatch($expression);
|
||||
|
||||
list(, $types) = $valueVisitor->getParamsAndTypes();
|
||||
[, $types] = $valueVisitor->getParamsAndTypes();
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function delete(PersistentCollection $collection)
|
||||
{
|
||||
@@ -166,28 +168,6 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
return $persister->exists($element, $criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeElement(PersistentCollection $collection, $element)
|
||||
{
|
||||
$mapping = $collection->getMapping();
|
||||
|
||||
if ( ! $mapping['orphanRemoval']) {
|
||||
// no-op: this is not the owning side, therefore no operations should be applied
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->isValidEntityState($element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this
|
||||
->uow
|
||||
->getEntityPersister($mapping['targetEntity'])
|
||||
->delete($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -26,6 +26,8 @@ use Doctrine\Common\Proxy\Proxy as BaseProxy;
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @since 2.0
|
||||
*
|
||||
* @deprecated 2.7 This interface is being removed from the ORM and won't have any replacement, proxies will no longer implement it.
|
||||
*/
|
||||
interface Proxy extends BaseProxy
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
@@ -37,6 +38,8 @@ use Doctrine\ORM\Utility\IdentifierFlattener;
|
||||
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
|
||||
* @author Marco Pivetta <ocramius@gmail.com>
|
||||
* @since 2.0
|
||||
*
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*/
|
||||
class ProxyFactory extends AbstractProxyFactory
|
||||
{
|
||||
@@ -116,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)
|
||||
{
|
||||
@@ -170,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)
|
||||
{
|
||||
@@ -209,3 +210,5 @@ class ProxyFactory extends AbstractProxyFactory
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
interface_exists(ClassMetadata::class);
|
||||
|
||||
@@ -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;
|
||||
@@ -133,7 +136,7 @@ final class Query extends AbstractQuery
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
private $_state = self::STATE_CLEAN;
|
||||
private $_state = self::STATE_DIRTY;
|
||||
|
||||
/**
|
||||
* A snapshot of the parameter types the query was parsed with.
|
||||
@@ -145,7 +148,7 @@ final class Query extends AbstractQuery
|
||||
/**
|
||||
* Cached DQL query.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
private $_dql = null;
|
||||
|
||||
@@ -159,7 +162,7 @@ final class Query extends AbstractQuery
|
||||
/**
|
||||
* The first result to return (the "offset").
|
||||
*
|
||||
* @var integer
|
||||
* @var int|null
|
||||
*/
|
||||
private $_firstResult = null;
|
||||
|
||||
@@ -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;
|
||||
@@ -587,7 +592,7 @@ final class Query extends AbstractQuery
|
||||
/**
|
||||
* Returns the DQL query that is represented by this query object.
|
||||
*
|
||||
* @return string DQL query.
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDQL()
|
||||
{
|
||||
@@ -624,11 +629,11 @@ final class Query extends AbstractQuery
|
||||
/**
|
||||
* Sets the position of the first result to retrieve (the "offset").
|
||||
*
|
||||
* @param integer $firstResult The first result to return.
|
||||
* @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;
|
||||
@@ -640,7 +645,7 @@ final class Query extends AbstractQuery
|
||||
* Gets the position of the first result the query object was set to retrieve (the "offset").
|
||||
* Returns NULL if {@link setFirstResult} was not applied to this query.
|
||||
*
|
||||
* @return integer The position of the first result.
|
||||
* @return int|null The position of the first result.
|
||||
*/
|
||||
public function getFirstResult()
|
||||
{
|
||||
@@ -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()) {
|
||||
|
||||
@@ -105,7 +105,7 @@ class TrimFunction extends FunctionNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
* @return int
|
||||
*/
|
||||
private function getTrimMode()
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user