mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
335 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
609647a51a | ||
|
|
293299a314 | ||
|
|
0b7fe1862e | ||
|
|
866283d1a7 | ||
|
|
3676e3c571 | ||
|
|
d84f607487 | ||
|
|
42af7cabb7 | ||
|
|
32192c7b01 | ||
|
|
77843e45f3 | ||
|
|
1919eea0a9 | ||
|
|
62ed63bbbe | ||
|
|
081ec2ad26 | ||
|
|
e9537f4cde | ||
|
|
38ad3925e2 | ||
|
|
858b01f85e | ||
|
|
9f555ea8fb | ||
|
|
1f8c02f345 | ||
|
|
d81afdb6e3 | ||
|
|
0628204b43 | ||
|
|
816ecc6d6b | ||
|
|
f66263d859 | ||
|
|
8aa5aa2f57 | ||
|
|
96e31a3b30 | ||
|
|
a60a273423 | ||
|
|
17500f56ea | ||
|
|
fc2f724e2d | ||
|
|
7986fc64dd | ||
|
|
2f9e98754b | ||
|
|
bb5524099c | ||
|
|
3a8cafe228 | ||
|
|
8259a16681 | ||
|
|
5577d51c44 | ||
|
|
d1922a3065 | ||
|
|
597a63a86c | ||
|
|
6b220e3c90 | ||
|
|
6de4b68705 | ||
|
|
16c0151831 | ||
|
|
440b244ebc | ||
|
|
a616914887 | ||
|
|
fd0bdc69b0 | ||
|
|
f50803ccb9 | ||
|
|
eeefc6bc0f | ||
|
|
710dde83aa | ||
|
|
495cd06b9a | ||
|
|
fd7a14ad22 | ||
|
|
0d3ce5d4f8 | ||
|
|
f01d107edc | ||
|
|
3cc30c4024 | ||
|
|
d2de4ec03c | ||
|
|
64ee76e94e | ||
|
|
8e20e1598e | ||
|
|
24df74d61d | ||
|
|
442f073d25 | ||
|
|
a5161e9485 | ||
|
|
ddc7d953b9 | ||
|
|
db51ed4f4c | ||
|
|
6d27797b2e | ||
|
|
89250b8ca2 | ||
|
|
f7e4b61459 | ||
|
|
6b0afdbd58 | ||
|
|
d3cf17b26d | ||
|
|
bc61d7d21e | ||
|
|
5213228a64 | ||
|
|
dca7ddf969 | ||
|
|
e781639812 | ||
|
|
7848417488 | ||
|
|
56e5856ad7 | ||
|
|
b5987ad29a | ||
|
|
385bdd33f1 | ||
|
|
8c513a6523 | ||
|
|
1413b496d7 | ||
|
|
3b3056f910 | ||
|
|
fa5c37e972 | ||
|
|
f3e36debfe | ||
|
|
ca7abd04a2 | ||
|
|
a555626150 | ||
|
|
ec7a8a7a0f | ||
|
|
e94fa8588d | ||
|
|
f26946b477 | ||
|
|
efc83bce8e | ||
|
|
450cae2caa | ||
|
|
81ddeb426c | ||
|
|
42e63bf358 | ||
|
|
4978e0e336 | ||
|
|
eee87c376d | ||
|
|
0b9060c728 | ||
|
|
514f6b8c28 | ||
|
|
c1018fe299 | ||
|
|
075824f5b5 | ||
|
|
d6f4834476 | ||
|
|
9dadffe270 | ||
|
|
b6e7e6d723 | ||
|
|
710937d6f8 | ||
|
|
5d2d6642c8 | ||
|
|
4d56711d8c | ||
|
|
a157bc3fb3 | ||
|
|
1aeab391c7 | ||
|
|
a4ecd02349 | ||
|
|
bb21865cba | ||
|
|
606da9280d | ||
|
|
21708e43c4 | ||
|
|
8c59828f6c | ||
|
|
0877ecbe56 | ||
|
|
8eb69922e6 | ||
|
|
e9b6fd89a4 | ||
|
|
01a14327d2 | ||
|
|
4887359827 | ||
|
|
2df1071e7a | ||
|
|
5afe9b80a8 | ||
|
|
7fc359c2bb | ||
|
|
853b9f75ae | ||
|
|
584c4aeed1 | ||
|
|
44d2a83e09 | ||
|
|
c9c5157fda | ||
|
|
dba90c1a91 | ||
|
|
5f079c2061 | ||
|
|
55d477dc50 | ||
|
|
4da8d3be96 | ||
|
|
4aadba65ce | ||
|
|
814d8d4d39 | ||
|
|
dc411954ad | ||
|
|
da29eb675c | ||
|
|
b17e52ba6b | ||
|
|
7ef4afc688 | ||
|
|
4e138903d0 | ||
|
|
efb50b9bdd | ||
|
|
70bcff7410 | ||
|
|
1989531d4f | ||
|
|
f778d8cf98 | ||
|
|
18b32ab9db | ||
|
|
d738ecfcfe | ||
|
|
aa3ff458c7 | ||
|
|
f76bab2b73 | ||
|
|
0e06d6b67d | ||
|
|
5114dcee0b | ||
|
|
8bc74c624a | ||
|
|
6c0a5ecbf9 | ||
|
|
5f6501f842 | ||
|
|
4c3bd20801 | ||
|
|
f2abf6143b | ||
|
|
338deacb58 | ||
|
|
829d5fbb9f | ||
|
|
d220494edc | ||
|
|
c235901544 | ||
|
|
ba089e551a | ||
|
|
ee0b3f214d | ||
|
|
930fa831b2 | ||
|
|
98b404875f | ||
|
|
fcc5c106b4 | ||
|
|
5132f0deb0 | ||
|
|
fe8e313731 | ||
|
|
41f704cd96 | ||
|
|
1adb5c0c70 | ||
|
|
e5174af669 | ||
|
|
c3106f9fe7 | ||
|
|
cbf45dd97e | ||
|
|
3c0d140e52 | ||
|
|
33675ff4a9 | ||
|
|
5c74795893 | ||
|
|
3827dd769e | ||
|
|
6c9b29f237 | ||
|
|
2afe2dc8af | ||
|
|
cc3d872b95 | ||
|
|
8961bfe90c | ||
|
|
15e3a7e861 | ||
|
|
65dc154ce5 | ||
|
|
1280e005b6 | ||
|
|
79f53d5dae | ||
|
|
caaa0d6192 | ||
|
|
68d3a63957 | ||
|
|
bf2937e63a | ||
|
|
76b8a215c2 | ||
|
|
b163cea61c | ||
|
|
ed212ab924 | ||
|
|
dd0e02e912 | ||
|
|
aad875eea1 | ||
|
|
84ab535e56 | ||
|
|
a72a0c3597 | ||
|
|
6217285544 | ||
|
|
330c0bc67e | ||
|
|
b5595ca041 | ||
|
|
4dfbe13897 | ||
|
|
b64e1c9b1f | ||
|
|
b779b112f3 | ||
|
|
bf449bef7d | ||
|
|
152f91fa33 | ||
|
|
14d1eb5340 | ||
|
|
04e08640fb | ||
|
|
aa27b3a35f | ||
|
|
d76fc4ebf6 | ||
|
|
da0998c401 | ||
|
|
ae60cf005f | ||
|
|
ddd3066bc4 | ||
|
|
6662195936 | ||
|
|
cc011d8215 | ||
|
|
d831c126c9 | ||
|
|
10eae1a7ff | ||
|
|
d951aa05b9 | ||
|
|
be297b9fd3 | ||
|
|
125e18cf24 | ||
|
|
8fba9d6868 | ||
|
|
7f4f1cda71 | ||
|
|
4e137f77a5 | ||
|
|
a33aa15c79 | ||
|
|
255ce51526 | ||
|
|
1c905b0e0a | ||
|
|
7901790b97 | ||
|
|
cef1d2d740 | ||
|
|
8126882305 | ||
|
|
a9513692cb | ||
|
|
52c3d9d82a | ||
|
|
2f46e5a130 | ||
|
|
a3fa1d7faa | ||
|
|
c7c57be0c2 | ||
|
|
721794fb9c | ||
|
|
38e47fdeab | ||
|
|
9ac063d879 | ||
|
|
b52a8f8b9e | ||
|
|
70477d81e9 | ||
|
|
1b2771f964 | ||
|
|
9bc6f5b4ac | ||
|
|
9766b6b03e | ||
|
|
37c8953015 | ||
|
|
60c625be17 | ||
|
|
8b0d6a13c2 | ||
|
|
a7ac6ff8d9 | ||
|
|
222d544b0c | ||
|
|
a199ca3002 | ||
|
|
6f1fd7a81e | ||
|
|
2af6e4db38 | ||
|
|
b48dafded8 | ||
|
|
ffe1550a68 | ||
|
|
eef5a1db81 | ||
|
|
c2d053d185 | ||
|
|
77822d623e | ||
|
|
7b5fafffbe | ||
|
|
aba8d74017 | ||
|
|
a056552db9 | ||
|
|
1142a396d3 | ||
|
|
f01b7d254d | ||
|
|
ed34327941 | ||
|
|
1ea8424e07 | ||
|
|
b42cf99402 | ||
|
|
ba9f51a363 | ||
|
|
1ae74b8ec5 | ||
|
|
a64f315dfe | ||
|
|
6ca319a6f4 | ||
|
|
fceb279947 | ||
|
|
2977933119 | ||
|
|
5ac6fadf29 | ||
|
|
e59ed88251 | ||
|
|
a16aeaeac8 | ||
|
|
fca1ef78a7 | ||
|
|
a78e5bcf65 | ||
|
|
09b4a75ed3 | ||
|
|
b984b567b8 | ||
|
|
92c56164ee | ||
|
|
b2707509fc | ||
|
|
1d02139d2a | ||
|
|
7ed28dba50 | ||
|
|
f215515bab | ||
|
|
ffbfbfcda1 | ||
|
|
4a30f622ec | ||
|
|
aec3556502 | ||
|
|
33a19f1bf3 | ||
|
|
b6669746b7 | ||
|
|
25bd41a504 | ||
|
|
04573fc283 | ||
|
|
82362ee65e | ||
|
|
9ff0440aac | ||
|
|
2c40e917c8 | ||
|
|
5c06d46874 | ||
|
|
24c4ac4dd8 | ||
|
|
4fad7a1190 | ||
|
|
f36a8c879c | ||
|
|
fa4b945b94 | ||
|
|
7814cbf4ec | ||
|
|
979b3dcb8d | ||
|
|
8efdcb0555 | ||
|
|
3810a0b6f9 | ||
|
|
c9b644dced | ||
|
|
ae6de13c01 | ||
|
|
072c40357f | ||
|
|
ca94e82828 | ||
|
|
db0b9d13c6 | ||
|
|
6c17e47624 | ||
|
|
83d56d75e1 | ||
|
|
d593c33ffa | ||
|
|
6c925f5b60 | ||
|
|
82bf68d482 | ||
|
|
2ee936acb4 | ||
|
|
843bff4971 | ||
|
|
d679292861 | ||
|
|
65687821a7 | ||
|
|
ca0dffb53e | ||
|
|
01028cf3b8 | ||
|
|
84bfe7cbb9 | ||
|
|
1b3978e8c9 | ||
|
|
7f783b59c8 | ||
|
|
68662f5920 | ||
|
|
769b161dff | ||
|
|
9857cf971b | ||
|
|
f73dae9bc4 | ||
|
|
1c357b9fb3 | ||
|
|
3d031ed541 | ||
|
|
15ed97b7b1 | ||
|
|
9fd4af23e1 | ||
|
|
4206f01e7b | ||
|
|
7d4052c9e7 | ||
|
|
fc6feb5938 | ||
|
|
89b98bdff9 | ||
|
|
37572802cc | ||
|
|
a5bdc619c7 | ||
|
|
65a7c8882f | ||
|
|
2d6295c9db | ||
|
|
f0616626e0 | ||
|
|
a8ef69dbe6 | ||
|
|
c0a7317e8d | ||
|
|
843b0fcc16 | ||
|
|
b56de5b0e2 | ||
|
|
0b35e637b8 | ||
|
|
277614d9c2 | ||
|
|
29b8b0bffb | ||
|
|
b7ba018f0a | ||
|
|
72b1bf0c02 | ||
|
|
70241d3407 | ||
|
|
1d5d47964c | ||
|
|
c9c4203a1e | ||
|
|
091da8c420 | ||
|
|
515a3d8b8b | ||
|
|
603ab9a185 | ||
|
|
10d27c18ea | ||
|
|
ae9fb8ca21 | ||
|
|
c7f2a1d580 | ||
|
|
b3f441cb8b |
@@ -12,21 +12,33 @@
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.15",
|
||||
"branchName": "2.15.x",
|
||||
"slug": "2.15",
|
||||
"name": "2.17",
|
||||
"branchName": "2.17.x",
|
||||
"slug": "2.17",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.14",
|
||||
"branchName": "2.14.x",
|
||||
"slug": "2.14",
|
||||
"name": "2.16",
|
||||
"branchName": "2.16.x",
|
||||
"slug": "2.16",
|
||||
"current": true,
|
||||
"aliases": [
|
||||
"current",
|
||||
"stable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "2.15",
|
||||
"branchName": "2.15.x",
|
||||
"slug": "2.15",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.14",
|
||||
"branchName": "2.14.x",
|
||||
"slug": "2.14",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.13",
|
||||
"branchName": "2.13.x",
|
||||
|
||||
16
.github/workflows/continuous-integration.yml
vendored
16
.github/workflows/continuous-integration.yml
vendored
@@ -39,6 +39,7 @@ jobs:
|
||||
- "8.0"
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
dbal-version:
|
||||
- "default"
|
||||
extension:
|
||||
@@ -62,7 +63,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -111,6 +112,7 @@ jobs:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -143,7 +145,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -183,6 +185,7 @@ jobs:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -212,7 +215,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -252,6 +255,7 @@ jobs:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -281,7 +285,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -333,7 +337,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -363,7 +367,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
|
||||
48
.github/workflows/documentation.yml
vendored
Normal file
48
.github/workflows/documentation.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: "Documentation"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/documentation.yml
|
||||
- docs/**
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/documentation.yml
|
||||
- docs/**
|
||||
|
||||
jobs:
|
||||
validate-with-guides:
|
||||
name: "Validate documentation with phpDocumentor/guides"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.2"
|
||||
|
||||
- name: "Remove existing composer file"
|
||||
run: "rm composer.json"
|
||||
|
||||
- name: "Require phpdocumentor/guides-cli"
|
||||
run: "composer require --dev phpdocumentor/guides-cli --no-update"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
- name: "Add dummy title to the sidebar"
|
||||
run: |
|
||||
printf '%s\n%s\n\n%s\n' "Dummy title" "===========" "$(cat docs/en/sidebar.rst)" > docs/en/sidebar.rst
|
||||
|
||||
- name: "Run guides-cli"
|
||||
run: "vendor/bin/guides -vvv --no-progress docs/en 2>&1 | grep -v 'Unknown directive' | ( ! grep WARNING )"
|
||||
2
.github/workflows/phpbench.yml
vendored
2
.github/workflows/phpbench.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
|
||||
4
.github/workflows/static-analysis.yml
vendored
4
.github/workflows/static-analysis.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
|
||||
@@ -40,6 +40,11 @@ cd orm
|
||||
composer install
|
||||
```
|
||||
|
||||
You will also need to enable the PHP extension that provides the SQLite driver
|
||||
for PDO: `pdo_sqlite`. How to do so depends on your system, but checking that it
|
||||
is enabled can universally be done with `php -m`: that command should list the
|
||||
extension.
|
||||
|
||||
To run the testsuite against another database, copy the ``phpunit.xml.dist``
|
||||
to for example ``mysql.phpunit.xml`` and edit the parameters. You can
|
||||
take a look at the ``ci/github/phpunit`` directory for some examples. Then run:
|
||||
|
||||
22
README.md
22
README.md
@@ -1,7 +1,7 @@
|
||||
| [3.0.x][3.0] | [2.14.x][2.14] | [2.13.x][2.13] |
|
||||
| [3.0.x][3.0] | [2.16.x][2.16] | [2.15.x][2.15] |
|
||||
|:----------------:|:----------------:|:----------:|
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.14 image]][2.14] | [![Build status][2.13 image]][2.13] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.14 coverage image]][2.14 coverage] | [![Coverage Status][2.13 coverage image]][2.13 coverage] |
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.16 image]][2.16] | [![Build status][2.15 image]][2.15] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.16 coverage image]][2.16 coverage] | [![Coverage Status][2.15 coverage image]][2.15 coverage] |
|
||||
|
||||
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
|
||||
|
||||
@@ -22,11 +22,11 @@ without requiring unnecessary code duplication.
|
||||
[3.0]: https://github.com/doctrine/orm/tree/3.0.x
|
||||
[3.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.0.x/graph/badge.svg
|
||||
[3.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.0.x
|
||||
[2.14 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.14.x
|
||||
[2.14]: https://github.com/doctrine/orm/tree/2.14.x
|
||||
[2.14 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.14.x/graph/badge.svg
|
||||
[2.14 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.14.x
|
||||
[2.13 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.13.x
|
||||
[2.13]: https://github.com/doctrine/orm/tree/2.13.x
|
||||
[2.13 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.13.x/graph/badge.svg
|
||||
[2.13 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.13.x
|
||||
[2.16 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.16.x
|
||||
[2.16]: https://github.com/doctrine/orm/tree/2.16.x
|
||||
[2.16 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.16.x/graph/badge.svg
|
||||
[2.16 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.16.x
|
||||
[2.15 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.15.x
|
||||
[2.15]: https://github.com/doctrine/orm/tree/2.15.x
|
||||
[2.15 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.15.x/graph/badge.svg
|
||||
[2.15 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.15.x
|
||||
|
||||
84
UPGRADE.md
84
UPGRADE.md
@@ -1,3 +1,87 @@
|
||||
# Upgrade to 2.16
|
||||
|
||||
## Deprecated accepting duplicate IDs in the identity map
|
||||
|
||||
For any given entity class and ID value, there should be only one object instance
|
||||
representing the entity.
|
||||
|
||||
In https://github.com/doctrine/orm/pull/10785, a check was added that will guard this
|
||||
in the identity map. The most probable cause for violations of this rule are collisions
|
||||
of application-provided IDs.
|
||||
|
||||
In ORM 2.16.0, the check was added by throwing an exception. In ORM 2.16.1, this will be
|
||||
changed to a deprecation notice. ORM 3.0 will make it an exception again. Use
|
||||
`\Doctrine\ORM\Configuration::setRejectIdCollisionInIdentityMap()` if you want to opt-in
|
||||
to the new mode.
|
||||
|
||||
## Potential changes to the order in which `INSERT`s are executed
|
||||
|
||||
In https://github.com/doctrine/orm/pull/10547, the commit order computation was improved
|
||||
to fix a series of bugs where a correct (working) commit order was previously not found.
|
||||
Also, the new computation may get away with fewer queries being executed: By inserting
|
||||
referred-to entities first and using their ID values for foreign key fields in subsequent
|
||||
`INSERT` statements, additional `UPDATE` statements that were previously necessary can be
|
||||
avoided.
|
||||
|
||||
When using database-provided, auto-incrementing IDs, this may lead to IDs being assigned
|
||||
to entities in a different order than it was previously the case.
|
||||
|
||||
## Deprecated `\Doctrine\ORM\Internal\CommitOrderCalculator` and related classes
|
||||
|
||||
With changes made to the commit order computation, the internal classes
|
||||
`\Doctrine\ORM\Internal\CommitOrderCalculator`, `\Doctrine\ORM\Internal\CommitOrder\Edge`,
|
||||
`\Doctrine\ORM\Internal\CommitOrder\Vertex` and `\Doctrine\ORM\Internal\CommitOrder\VertexState`
|
||||
have been deprecated and will be removed in ORM 3.0.
|
||||
|
||||
## Deprecated returning post insert IDs from `EntityPersister::executeInserts()`
|
||||
|
||||
Persisters implementing `\Doctrine\ORM\Persisters\Entity\EntityPersister` should no longer
|
||||
return an array of post insert IDs from their `::executeInserts()` method. Make the
|
||||
persister call `Doctrine\ORM\UnitOfWork::assignPostInsertId()` instead.
|
||||
|
||||
## Changing the way how reflection-based mapping drivers report fields, deprecated the "old" mode
|
||||
|
||||
In ORM 3.0, a change will be made regarding how the `AttributeDriver` reports field mappings.
|
||||
This change is necessary to be able to detect (and reject) some invalid mapping configurations.
|
||||
|
||||
To avoid surprises during 2.x upgrades, the new mode is opt-in. It can be activated on the
|
||||
`AttributeDriver` and `AnnotationDriver` by setting the `$reportFieldsWhereDeclared`
|
||||
constructor parameter to `true`. It will cause `MappingException`s to be thrown when invalid
|
||||
configurations are detected.
|
||||
|
||||
Not enabling the new mode will cause a deprecation notice to be raised. In ORM 3.0,
|
||||
only the new mode will be available.
|
||||
|
||||
# Upgrade to 2.15
|
||||
|
||||
## Deprecated configuring `JoinColumn` on the inverse side of one-to-one associations
|
||||
|
||||
For one-to-one associations, the side using the `mappedBy` attribute is the inverse side.
|
||||
The owning side is the entity with the table containing the foreign key. Using `JoinColumn`
|
||||
configuration on the _inverse_ side now triggers a deprecation notice and will be an error
|
||||
in 3.0.
|
||||
|
||||
## Deprecated overriding fields or associations not declared in mapped superclasses
|
||||
|
||||
As stated in the documentation, fields and associations may only be overridden when being inherited
|
||||
from mapped superclasses. Overriding them for parent entity classes now triggers a deprecation notice
|
||||
and will be an error in 3.0.
|
||||
|
||||
## Deprecated undeclared entity inheritance
|
||||
|
||||
As soon as an entity class inherits from another entity class, inheritance has to
|
||||
be declared by adding the appropriate configuration for the root entity.
|
||||
|
||||
## Deprecated stubs for "concrete table inheritance"
|
||||
|
||||
This third way of mapping class inheritance was never implemented. Code stubs are
|
||||
now deprecated and will be removed in 3.0.
|
||||
|
||||
* `\Doctrine\ORM\Mapping\ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS` constant
|
||||
* `\Doctrine\ORM\Mapping\ClassMetadataInfo::isInheritanceTypeTablePerClass()` method
|
||||
* Using `TABLE_PER_CLASS` as the value for the `InheritanceType` attribute or annotation
|
||||
or in XML configuration files.
|
||||
|
||||
# Upgrade to 2.14
|
||||
|
||||
## Deprecated `Doctrine\ORM\Persisters\Exception\UnrecognizedField::byName($field)` method.
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
"composer-runtime-api": "^2",
|
||||
"ext-ctype": "*",
|
||||
"doctrine/cache": "^1.12.1 || ^2.1.1",
|
||||
"doctrine/collections": "^1.5 || ^2.0",
|
||||
"doctrine/collections": "^1.5 || ^2.1",
|
||||
"doctrine/common": "^3.0.3",
|
||||
"doctrine/dbal": "^2.13.1 || ^3.2",
|
||||
"doctrine/deprecations": "^0.5.3 || ^1",
|
||||
"doctrine/event-manager": "^1.2 || ^2",
|
||||
"doctrine/inflector": "^1.4 || ^2.0",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
"doctrine/lexer": "^1.2.3 || ^2",
|
||||
"doctrine/instantiator": "^1.3 || ^2",
|
||||
"doctrine/lexer": "^2",
|
||||
"doctrine/persistence": "^2.4 || ^3",
|
||||
"psr/cache": "^1 || ^2 || ^3",
|
||||
"symfony/console": "^4.2 || ^5.0 || ^6.0",
|
||||
@@ -40,16 +40,16 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "^1.13 || ^2",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^11.0",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^12.0",
|
||||
"phpbench/phpbench": "^0.16.10 || ^1.0",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.10.6",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.10.35",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.7.2",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
|
||||
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2",
|
||||
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
|
||||
"vimeo/psalm": "4.30.0 || 5.9.0"
|
||||
"vimeo/psalm": "4.30.0 || 5.15.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/annotations": "<1.13 || >= 3.0"
|
||||
|
||||
@@ -211,7 +211,7 @@ Now look at the following test-code for our entities:
|
||||
{
|
||||
public function testAddEntry()
|
||||
{
|
||||
$account = new Account("123456", $maxCredit = 200);
|
||||
$account = new Account("123456", maxCredit: 200);
|
||||
$this->assertEquals(0, $account->getBalance());
|
||||
|
||||
$account->addEntry(500);
|
||||
@@ -223,7 +223,7 @@ Now look at the following test-code for our entities:
|
||||
|
||||
public function testExceedMaxLimit()
|
||||
{
|
||||
$account = new Account("123456", $maxCredit = 200);
|
||||
$account = new Account("123456", maxCredit: 200);
|
||||
|
||||
$this->expectException(Exception::class);
|
||||
$account->addEntry(-1000);
|
||||
|
||||
@@ -13,7 +13,7 @@ for all our domain objects.
|
||||
.. note::
|
||||
|
||||
The notify change tracking policy is deprecated and will be removed in ORM 3.0.
|
||||
(`Details <https://github.com/doctrine/orm/issues/8383>`_)
|
||||
(\ `Details <https://github.com/doctrine/orm/issues/8383>`_)
|
||||
|
||||
Implementing NotifyPropertyChanged
|
||||
----------------------------------
|
||||
|
||||
@@ -58,6 +58,10 @@ First Attributes:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
|
||||
use Doctrine\ORM\Mapping\PrePersist;
|
||||
use Doctrine\ORM\Mapping\PreUpdate;
|
||||
|
||||
#[Entity]
|
||||
#[HasLifecycleCallbacks]
|
||||
|
||||
@@ -18,8 +18,8 @@ Doctrine ORM don't panic. You can get help from different sources:
|
||||
- Report a bug on `GitHub <https://github.com/doctrine/orm/issues>`_.
|
||||
- On `StackOverflow <https://stackoverflow.com/questions/tagged/doctrine-orm>`_
|
||||
|
||||
If you need more structure over the different topics you can browse the :doc:`table
|
||||
of contents <toc>`.
|
||||
If you need more structure over the different topics you can browse the table
|
||||
of contents.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
@@ -34,32 +34,32 @@ Mapping Objects onto a Database
|
||||
-------------------------------
|
||||
|
||||
* **Mapping**:
|
||||
:doc:`Objects <reference/basic-mapping>` |
|
||||
:doc:`Associations <reference/association-mapping>` |
|
||||
:doc:`Objects <reference/basic-mapping>` \|
|
||||
:doc:`Associations <reference/association-mapping>` \|
|
||||
:doc:`Inheritance <reference/inheritance-mapping>`
|
||||
|
||||
* **Drivers**:
|
||||
:doc:`Docblock Annotations <reference/annotations-reference>` |
|
||||
:doc:`Attributes <reference/attributes-reference>` |
|
||||
:doc:`XML <reference/xml-mapping>` |
|
||||
:doc:`YAML <reference/yaml-mapping>` |
|
||||
:doc:`Docblock Annotations <reference/annotations-reference>` \|
|
||||
:doc:`Attributes <reference/attributes-reference>` \|
|
||||
:doc:`XML <reference/xml-mapping>` \|
|
||||
:doc:`YAML <reference/yaml-mapping>` \|
|
||||
:doc:`PHP <reference/php-mapping>`
|
||||
|
||||
Working with Objects
|
||||
--------------------
|
||||
|
||||
* **Basic Reference**:
|
||||
:doc:`Entities <reference/working-with-objects>` |
|
||||
:doc:`Associations <reference/working-with-associations>` |
|
||||
:doc:`Entities <reference/working-with-objects>` \|
|
||||
:doc:`Associations <reference/working-with-associations>` \|
|
||||
:doc:`Events <reference/events>`
|
||||
|
||||
* **Query Reference**:
|
||||
:doc:`DQL <reference/dql-doctrine-query-language>` |
|
||||
:doc:`QueryBuilder <reference/query-builder>` |
|
||||
:doc:`DQL <reference/dql-doctrine-query-language>` \|
|
||||
:doc:`QueryBuilder <reference/query-builder>` \|
|
||||
:doc:`Native SQL <reference/native-sql>`
|
||||
|
||||
* **Internals**:
|
||||
:doc:`Internals explained <reference/unitofwork>` |
|
||||
:doc:`Internals explained <reference/unitofwork>` \|
|
||||
:doc:`Associations <reference/unitofwork-associations>`
|
||||
|
||||
Advanced Topics
|
||||
@@ -102,20 +102,20 @@ Cookbook
|
||||
--------
|
||||
|
||||
* **Patterns**:
|
||||
:doc:`Aggregate Fields <cookbook/aggregate-fields>` |
|
||||
:doc:`Decorator Pattern <cookbook/decorator-pattern>` |
|
||||
:doc:`Aggregate Fields <cookbook/aggregate-fields>` \|
|
||||
:doc:`Decorator Pattern <cookbook/decorator-pattern>` \|
|
||||
:doc:`Strategy Pattern <cookbook/strategy-cookbook-introduction>`
|
||||
|
||||
* **DQL Extension Points**:
|
||||
:doc:`DQL Custom Walkers <cookbook/dql-custom-walkers>` |
|
||||
:doc:`DQL Custom Walkers <cookbook/dql-custom-walkers>` \|
|
||||
:doc:`DQL User-Defined-Functions <cookbook/dql-user-defined-functions>`
|
||||
|
||||
* **Implementation**:
|
||||
:doc:`Array Access <cookbook/implementing-arrayaccess-for-domain-objects>` |
|
||||
:doc:`Notify ChangeTracking Example <cookbook/implementing-the-notify-changetracking-policy>` |
|
||||
:doc:`Working with DateTime <cookbook/working-with-datetime>` |
|
||||
:doc:`Validation <cookbook/validation-of-entities>` |
|
||||
:doc:`Entities in the Session <cookbook/entities-in-session>` |
|
||||
:doc:`Array Access <cookbook/implementing-arrayaccess-for-domain-objects>` \|
|
||||
:doc:`Notify ChangeTracking Example <cookbook/implementing-the-notify-changetracking-policy>` \|
|
||||
:doc:`Working with DateTime <cookbook/working-with-datetime>` \|
|
||||
:doc:`Validation <cookbook/validation-of-entities>` \|
|
||||
:doc:`Entities in the Session <cookbook/entities-in-session>` \|
|
||||
:doc:`Keeping your Modules independent <cookbook/resolve-target-entity-listener>`
|
||||
|
||||
* **Hidden Gems**
|
||||
@@ -124,5 +124,3 @@ Cookbook
|
||||
* **Custom Datatypes**
|
||||
:doc:`MySQL Enums <cookbook/mysql-enums>`
|
||||
:doc:`Advanced Field Value Conversion <cookbook/advanced-field-value-conversion-using-custom-mapping-types>`
|
||||
|
||||
.. include:: toc.rst
|
||||
|
||||
@@ -29,7 +29,7 @@ steps of configuration.
|
||||
|
||||
$config = new Configuration;
|
||||
$config->setMetadataCache($metadataCache);
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']);
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
$config->setQueryCache($queryCache);
|
||||
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
|
||||
@@ -134,7 +134,7 @@ The attribute driver can be injected in the ``Doctrine\ORM\Configuration``:
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
|
||||
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']);
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
|
||||
The path information to the entities is required for the attribute
|
||||
@@ -311,10 +311,12 @@ Reference Proxies
|
||||
|
||||
The method ``EntityManager#getReference($entityName, $identifier)``
|
||||
lets you obtain a reference to an entity for which the identifier
|
||||
is known, without loading that entity from the database. This is
|
||||
useful, for example, as a performance enhancement, when you want to
|
||||
establish an association to an entity for which you have the
|
||||
identifier. You could simply do this:
|
||||
is known, without necessarily loading that entity from the database.
|
||||
This is useful, for example, as a performance enhancement, when you
|
||||
want to establish an association to an entity for which you have the
|
||||
identifier.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -324,15 +326,33 @@ identifier. You could simply do this:
|
||||
$item = $em->getReference('MyProject\Model\Item', $itemId);
|
||||
$cart->addItem($item);
|
||||
|
||||
Here, we added an Item to a Cart without loading the Item from the
|
||||
database. If you access any state that isn't yet available in the
|
||||
Item instance, the proxying mechanism would fully initialize the
|
||||
object's state transparently from the database. Here
|
||||
$item is actually an instance of the proxy class that was generated
|
||||
for the Item class but your code does not need to care. In fact it
|
||||
**should not care**. Proxy objects should be transparent to your
|
||||
Whether the object being returned from ``EntityManager#getReference()``
|
||||
is a proxy or a direct instance of the entity class may depend on different
|
||||
factors, including whether the entity has already been loaded into memory
|
||||
or entity inheritance being used. But your code does not need to care
|
||||
and in fact it **should not care**. Proxy objects should be transparent to your
|
||||
code.
|
||||
|
||||
When using the ``EntityManager#getReference()`` method, you need to be aware
|
||||
of a few peculiarities.
|
||||
|
||||
At the best case, the ORM can avoid querying the database at all. But, that
|
||||
also means that this method will not throw an exception when an invalid value
|
||||
for the ``$identifier`` parameter is passed. ``$identifier`` values are
|
||||
not checked and there is no guarantee that the requested entity instance even
|
||||
exists – the method will still return a proxy object.
|
||||
|
||||
Its only when the proxy has to be fully initialized or associations cannot
|
||||
be written to the database that invalid ``$identifier`` values may lead to
|
||||
exceptions.
|
||||
|
||||
The ``EntityManager#getReference()`` is mostly useful when you only
|
||||
need a reference to some entity to make an association, like in the example
|
||||
above. In that case, it can save you from loading data from the database
|
||||
that you don't need. But remember – as soon as you read any property values
|
||||
besides those making up the ID, a database request will be made to initialize
|
||||
all fields.
|
||||
|
||||
Association proxies
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -545,12 +545,12 @@ has meaning in the SchemaTool schema generation context.
|
||||
Required attributes:
|
||||
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **fields**: Array of fields. Exactly one of **fields**, **columns** is required.
|
||||
- **columns**: Array of columns. Exactly one of **fields**, **columns** is required.
|
||||
|
||||
Optional attributes:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
@@ -1316,12 +1316,12 @@ context.
|
||||
Required attributes:
|
||||
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **fields**: Array of fields. Exactly one of **fields**, **columns** is required.
|
||||
- **columns**: Array of columns. Exactly one of **fields**, **columns** is required.
|
||||
|
||||
Optional attributes:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
|
||||
@@ -24,28 +24,34 @@ performance it is also recommended that you use APC with PHP.
|
||||
Doctrine ORM Packages
|
||||
-------------------
|
||||
|
||||
Doctrine ORM is divided into three main packages.
|
||||
Doctrine ORM is divided into four main packages.
|
||||
|
||||
- Common
|
||||
- DBAL (includes Common)
|
||||
- ORM (includes DBAL+Common)
|
||||
- `Collections <https://www.doctrine-project.org/projects/doctrine-collections/en/stable/index.html>`_
|
||||
- `Event Manager <https://www.doctrine-project.org/projects/doctrine-event-manager/en/stable/index.html>`_
|
||||
- `Persistence <https://www.doctrine-project.org/projects/doctrine-persistence/en/stable/index.html>`_
|
||||
- `DBAL <https://www.doctrine-project.org/projects/doctrine-dbal/en/stable/index.html>`_
|
||||
- ORM (depends on DBAL+Persistence+Collections)
|
||||
|
||||
This manual mainly covers the ORM package, sometimes touching parts
|
||||
of the underlying DBAL and Common packages. The Doctrine code base
|
||||
of the underlying DBAL and Persistence packages. The Doctrine code base
|
||||
is split in to these packages for a few reasons and they are to...
|
||||
|
||||
|
||||
- ...make things more maintainable and decoupled
|
||||
- ...allow you to use the code in Doctrine Common without the ORM
|
||||
or DBAL
|
||||
- ...allow you to use the code in Doctrine Persistence and Collections
|
||||
without the ORM or DBAL
|
||||
- ...allow you to use the DBAL without the ORM
|
||||
|
||||
The Common Package
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
Collection, Event Manager and Persistence
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Common package contains highly reusable components that have no
|
||||
dependencies beyond the package itself (and PHP, of course). The
|
||||
root namespace of the Common package is ``Doctrine\Common``.
|
||||
The Collection, Event Manager and Persistence packages contain highly
|
||||
reusable components that have no dependencies beyond the packages
|
||||
themselves (and PHP, of course). The root namespace of the Persistence
|
||||
package is ``Doctrine\Persistence``. The root namespace of the
|
||||
Collection package is ``Doctrine\Common\Collections``, for historical
|
||||
reasons. The root namespace of the Event Manager package is just
|
||||
``Doctrine\Common``, also for historical reasons.
|
||||
|
||||
The DBAL Package
|
||||
~~~~~~~~~~~~~~~~
|
||||
@@ -102,7 +108,7 @@ persistent entity state and mapping information for its subclasses,
|
||||
but which is not itself an entity.
|
||||
|
||||
Mapped superclasses are explained in greater detail in the chapter
|
||||
on :doc:`inheritance mapping <reference/inheritance-mapping>`.
|
||||
on :doc:`inheritance mapping </reference/inheritance-mapping>`.
|
||||
|
||||
Transient Classes
|
||||
~~~~~~~~~~~~~~~~~
|
||||
@@ -199,5 +205,3 @@ typical implementation of the
|
||||
to keep track of all the things that need to be done the next time
|
||||
``flush`` is invoked. You usually do not directly interact with a
|
||||
``UnitOfWork`` but with the ``EntityManager`` instead.
|
||||
|
||||
|
||||
|
||||
@@ -881,6 +881,15 @@ Generated MySQL Schema:
|
||||
replaced by one-to-many/many-to-one associations between the 3
|
||||
participating classes.
|
||||
|
||||
.. note::
|
||||
|
||||
For many-to-many associations, the ORM takes care of managing rows
|
||||
in the join table connecting both sides. Due to the way it deals
|
||||
with entity removals, database-level constraints may not work the
|
||||
way one might intuitively assume. Thus, be sure not to miss the section
|
||||
on :ref:`join table management <remove_object_many_to_many_join_tables>`.
|
||||
|
||||
|
||||
Many-To-Many, Bidirectional
|
||||
---------------------------
|
||||
|
||||
@@ -1019,6 +1028,15 @@ one is bidirectional.
|
||||
The MySQL schema is exactly the same as for the Many-To-Many
|
||||
uni-directional case above.
|
||||
|
||||
.. note::
|
||||
|
||||
For many-to-many associations, the ORM takes care of managing rows
|
||||
in the join table connecting both sides. Due to the way it deals
|
||||
with entity removals, database-level constraints may not work the
|
||||
way one might intuitively assume. Thus, be sure not to miss the section
|
||||
on :ref:`join table management <remove_object_many_to_many_join_tables>`.
|
||||
|
||||
|
||||
Owning and Inverse Side on a ManyToMany Association
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -368,6 +368,7 @@ Optional parameters:
|
||||
- **length**: By default this is 255.
|
||||
- **columnDefinition**: By default this is null the definition according to the type will be used. This option allows to override it.
|
||||
- **enumType**: By default this is `null`. Allows to map discriminatorColumn value to PHP enum
|
||||
- **options**: See "options" attribute on :ref:`#[Column] <attrref_column>`.
|
||||
|
||||
.. _attrref_discriminatormap:
|
||||
|
||||
@@ -539,13 +540,13 @@ has meaning in the ``SchemaTool`` schema generation context.
|
||||
|
||||
Required parameters:
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **fields**: Array of fields. Exactly one of **fields, columns** is required.
|
||||
- **columns**: Array of columns. Exactly one of **fields, columns** is required.
|
||||
|
||||
|
||||
Optional parameters:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
@@ -575,7 +576,7 @@ Example with partial indexes:
|
||||
|
||||
#[Index(name: "search_idx", columns: ["category"],
|
||||
options: [
|
||||
"where": "((category IS NOT NULL))"
|
||||
"where" => "((category IS NOT NULL))"
|
||||
]
|
||||
)]
|
||||
class ECommerceProduct
|
||||
@@ -1103,11 +1104,12 @@ context.
|
||||
|
||||
Required parameters:
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **columns**: Array of columns.
|
||||
- **fields**: Array of fields (the names of the properties, used in the entity class).
|
||||
- **columns**: Array of columns (the names of the columns, used in the schema).
|
||||
|
||||
Optional parameters:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
|
||||
@@ -47,8 +47,7 @@ mapping metadata:
|
||||
- :doc:`Attributes <attributes-reference>`
|
||||
- :doc:`XML <xml-mapping>`
|
||||
- :doc:`PHP code <php-mapping>`
|
||||
- :doc:`Docblock Annotations <annotations-reference>` (deprecated and
|
||||
will be removed in ``doctrine/orm`` 3.0)
|
||||
- :doc:`Docblock Annotations <annotations-reference>` (deprecated and will be removed in ``doctrine/orm`` 3.0)
|
||||
- :doc:`YAML <yaml-mapping>` (deprecated and will be removed in ``doctrine/orm`` 3.0.)
|
||||
|
||||
This manual will usually show mapping metadata via attributes, though
|
||||
@@ -460,7 +459,7 @@ Here is the list of possible generation strategies:
|
||||
a new entity is passed to ``EntityManager#persist``. NONE is the
|
||||
same as leaving off the ``#[GeneratedValue]`` entirely.
|
||||
- ``CUSTOM``: With this option, you can use the ``#[CustomIdGenerator]`` attribute.
|
||||
It will allow you to pass a :doc:`class of your own to generate the identifiers.<_annref_customidgenerator>`
|
||||
It will allow you to pass a :ref:`class of your own to generate the identifiers.<annref_customidgenerator>`
|
||||
|
||||
Sequence Generator
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -86,7 +86,7 @@ with the batching strategy that was already used for bulk inserts:
|
||||
|
||||
<?php
|
||||
$batchSize = 20;
|
||||
$i = 1;
|
||||
$i = 0;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
foreach ($q->toIterable() as $user) {
|
||||
$user->increaseCredit();
|
||||
@@ -145,7 +145,7 @@ The following example shows how to do this:
|
||||
|
||||
<?php
|
||||
$batchSize = 20;
|
||||
$i = 1;
|
||||
$i = 0;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
foreach($q->toIterable() as $row) {
|
||||
$em->remove($row);
|
||||
|
||||
@@ -63,7 +63,7 @@ Notify
|
||||
.. note::
|
||||
|
||||
The notify change tracking policy is deprecated and will be removed in ORM 3.0.
|
||||
(`Details <https://github.com/doctrine/orm/issues/8383>`_)
|
||||
(\ `Details <https://github.com/doctrine/orm/issues/8383>`_)
|
||||
|
||||
This policy is based on the assumption that the entities notify
|
||||
interested listeners of changes to their properties. For that
|
||||
|
||||
@@ -104,7 +104,7 @@ Inside the ``ORMSetup`` methods several assumptions are made:
|
||||
In order to have ``ORMSetup`` configure the cache automatically, the library ``symfony/cache``
|
||||
has to be installed as a dependency.
|
||||
|
||||
If you want to configure Doctrine in more detail, take a look at the :doc:`Advanced Configuration <reference/advanced-configuration>` section.
|
||||
If you want to configure Doctrine in more detail, take a look at the :doc:`Advanced Configuration </reference/advanced-configuration>` section.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
@@ -1304,14 +1304,13 @@ creating a class which extends ``AbstractHydrator``:
|
||||
<?php
|
||||
namespace MyProject\Hydrators;
|
||||
|
||||
use Doctrine\DBAL\FetchMode;
|
||||
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
|
||||
|
||||
class CustomHydrator extends AbstractHydrator
|
||||
{
|
||||
protected function _hydrateAll()
|
||||
{
|
||||
return $this->_stmt->fetchAll(FetchMode::FETCH_ASSOC);
|
||||
return $this->_stmt->fetchAllAssociative();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1337,8 +1336,8 @@ There are situations when a query you want to execute returns a
|
||||
very large result-set that needs to be processed. All the
|
||||
previously described hydration modes completely load a result-set
|
||||
into memory which might not be feasible with large result sets. See
|
||||
the `Batch Processing <batch-processing.html>`_ section on details how
|
||||
to iterate large result sets.
|
||||
the :doc:`Batch Processing </reference/batch-processing>` section on
|
||||
details how to iterate large result sets.
|
||||
|
||||
Functions
|
||||
~~~~~~~~~
|
||||
@@ -1382,7 +1381,7 @@ Result Cache API:
|
||||
$query->setResultCacheDriver(new ApcCache());
|
||||
|
||||
$query->useResultCache(true)
|
||||
->setResultCacheLifeTime($seconds = 3600);
|
||||
->setResultCacheLifeTime(3600);
|
||||
|
||||
$result = $query->getResult(); // cache miss
|
||||
|
||||
@@ -1393,7 +1392,7 @@ Result Cache API:
|
||||
$result = $query->getResult(); // saved in given result cache id.
|
||||
|
||||
// or call useResultCache() with all parameters:
|
||||
$query->useResultCache(true, $seconds = 3600, 'my_query_result');
|
||||
$query->useResultCache(true, 3600, 'my_query_result');
|
||||
$result = $query->getResult(); // cache hit!
|
||||
|
||||
// Introspection
|
||||
@@ -1426,7 +1425,7 @@ userland:
|
||||
reloading this data. Partially loaded objects have to be passed to
|
||||
``EntityManager::refresh()`` if they are to be reloaded fully from
|
||||
the database. This query hint is deprecated and will be removed
|
||||
in the future (`Details <https://github.com/doctrine/orm/issues/8471>`_)
|
||||
in the future (\ `Details <https://github.com/doctrine/orm/issues/8471>`_)
|
||||
- ``Query::HINT_REFRESH`` - This query is used internally by
|
||||
``EntityManager::refresh()`` and can be used in userland as well.
|
||||
If you specify this hint and a query returns the data for an entity
|
||||
@@ -1458,7 +1457,7 @@ several methods to interact with it:
|
||||
|
||||
- ``Query::setQueryCacheDriver($driver)`` - Allows to set a Cache
|
||||
instance
|
||||
- ``Query::setQueryCacheLifeTime($seconds = 3600)`` - Set lifetime
|
||||
- ``Query::setQueryCacheLifeTime($seconds)`` - Set lifetime
|
||||
of the query caching.
|
||||
- ``Query::expireQueryCache($bool)`` - Enforce the expiring of the
|
||||
query cache if set to true.
|
||||
|
||||
@@ -215,6 +215,10 @@ specific to a particular entity class's lifecycle.
|
||||
<?php
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Event\PrePersistEventArgs;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
|
||||
use Doctrine\ORM\Mapping\PrePersist;
|
||||
use Doctrine\ORM\Mapping\PreUpdate;
|
||||
|
||||
#[Entity]
|
||||
#[HasLifecycleCallbacks]
|
||||
@@ -281,10 +285,10 @@ specific to a particular entity class's lifecycle.
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="User">
|
||||
<!-- ... -->
|
||||
<lifecycle-callbacks>
|
||||
@@ -453,13 +457,12 @@ prePersist
|
||||
|
||||
There are two ways for the ``prePersist`` event to be triggered:
|
||||
|
||||
- One is obviously when you call ``EntityManager::persist()``. The
|
||||
event is also called for all :ref:`cascaded associations<transitive-persistence>`.
|
||||
- The other is inside the
|
||||
``flush()`` method when changes to associations are computed and
|
||||
this association is marked as :ref:`cascade: persist<transitive-persistence>`. Any new entity found
|
||||
during this operation is also persisted and ``prePersist`` called
|
||||
on it. This is called :ref:`persistence by reachability<persistence-by-reachability>`.
|
||||
- One is when you call ``EntityManager::persist()``. The
|
||||
event is also called for all :ref:`cascaded associations<transitive-persistence>`.
|
||||
- The other is inside the ``flush()`` method when changes to associations are computed and
|
||||
this association is marked as :ref:`cascade: persist<transitive-persistence>`. Any new entity found
|
||||
during this operation is also persisted and ``prePersist`` called
|
||||
on it. This is called :ref:`persistence by reachability<persistence-by-reachability>`.
|
||||
|
||||
In both cases you get passed a ``PrePersistEventArgs`` instance
|
||||
which has access to the entity and the entity manager.
|
||||
@@ -705,13 +708,21 @@ not directly mapped by Doctrine.
|
||||
- The ``postUpdate`` event occurs after the database
|
||||
update operations to entity data. It is not called for a DQL
|
||||
``UPDATE`` statement.
|
||||
- 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.
|
||||
- The ``postPersist`` event occurs for an entity after the entity has
|
||||
been made persistent. It will be invoked after all database insert
|
||||
operations for new entities have been performed. Generated primary
|
||||
key values will be available for all entities at the time this
|
||||
event is triggered.
|
||||
- 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.
|
||||
entity has been deleted. It will be invoked after all database
|
||||
delete operations for entity rows have been executed. This event is
|
||||
not called for a DQL ``DELETE`` statement.
|
||||
|
||||
.. note::
|
||||
|
||||
At the time ``postPersist`` is called, there may still be collection and/or
|
||||
"extra" updates pending. The database may not yet be completely in
|
||||
sync with the entity states in memory, not even for the new entities.
|
||||
|
||||
.. warning::
|
||||
|
||||
@@ -720,6 +731,19 @@ not directly mapped by Doctrine.
|
||||
cascade remove relations. In this case, you should load yourself the proxy in
|
||||
the associated ``pre*`` event.
|
||||
|
||||
.. warning::
|
||||
|
||||
Making changes to entities and calling ``EntityManager::flush()`` from within
|
||||
``post*`` event handlers is strongly discouraged, and might be deprecated and
|
||||
eventually prevented in the future.
|
||||
|
||||
The reason is that it causes re-entrance into ``UnitOfWork::commit()`` while a commit
|
||||
is currently being processed. The ``UnitOfWork`` was never designed to support this,
|
||||
and its behavior in this situation is not covered by any tests.
|
||||
|
||||
This may lead to entity or collection updates being missed, applied only in parts and
|
||||
changes being lost at the end of the commit phase.
|
||||
|
||||
.. _reference-events-post-load:
|
||||
|
||||
postLoad
|
||||
|
||||
@@ -13,11 +13,10 @@ Database Schema
|
||||
How do I set the charset and collation for MySQL tables?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can't set these values with attributes, annotations or inside yml or
|
||||
xml mapping files. To make a database work with the default charset and
|
||||
collation you should configure MySQL to use it as default charset, or
|
||||
create the database with charset and collation details. This way they
|
||||
get inherited to all newly created database tables and columns.
|
||||
In your mapping configuration, the column definition (for example, the
|
||||
``#[Column]`` attribute) has an ``options`` parameter where you can specify
|
||||
the ``charset`` and ``collation``. The default values are ``utf8`` and
|
||||
``utf8_unicode_ci``, respectively.
|
||||
|
||||
Entity Classes
|
||||
--------------
|
||||
|
||||
@@ -93,3 +93,34 @@ object.
|
||||
want to refresh or reload an object after having modified a filter or the
|
||||
FilterCollection, then you should clear the EntityManager and re-fetch your
|
||||
entities, having the new rules for filtering applied.
|
||||
|
||||
|
||||
Suspending/Restoring Filters
|
||||
----------------------------
|
||||
When a filter is disabled, the instance is fully deleted and all the filter
|
||||
parameters previously set are lost. Then, if you enable it again, a new filter
|
||||
is created without the previous filter parameters. If you want to keep a filter
|
||||
(in order to use it later) but temporary disable it, you'll need to use the
|
||||
``FilterCollection#suspend($name)`` and ``FilterCollection#restore($name)``
|
||||
methods instead.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$filter = $em->getFilters()->enable("locale");
|
||||
$filter->setParameter('locale', 'en');
|
||||
|
||||
// Temporary suspend the filter
|
||||
$filter = $em->getFilters()->suspend("locale");
|
||||
|
||||
// Do things
|
||||
|
||||
// Then restore it, the locale parameter will still be set
|
||||
$filter = $em->getFilters()->restore("locale");
|
||||
|
||||
.. warning::
|
||||
If you enable a previously disabled filter, doctrine will create a new
|
||||
one without keeping any of the previously parameter set with
|
||||
``SQLFilter#setParameter()`` or ``SQLFilter#getParameterList()``. If you
|
||||
want to restore the previously disabled filter instead, you must use the
|
||||
``FilterCollection#restore($name)`` method.
|
||||
|
||||
@@ -91,7 +91,7 @@ Apply Best Practices
|
||||
A lot of the points mentioned in the Best Practices chapter will
|
||||
also positively affect the performance of Doctrine.
|
||||
|
||||
See :doc:`Best Practices <reference/best-practices>`
|
||||
See :doc:`Best Practices </reference/best-practices>`
|
||||
|
||||
Change Tracking policies
|
||||
------------------------
|
||||
|
||||
@@ -15,27 +15,37 @@ is common to multiple entity classes.
|
||||
|
||||
Mapped superclasses, just as regular, non-mapped classes, can
|
||||
appear in the middle of an otherwise mapped inheritance hierarchy
|
||||
(through Single Table Inheritance or Class Table Inheritance).
|
||||
(through Single Table Inheritance or Class Table Inheritance). They
|
||||
are not query-able, and need not have an ``#[Id]`` property.
|
||||
|
||||
No database table will be created for a mapped superclass itself,
|
||||
only for entity classes inheriting from it. Also, a mapped superclass
|
||||
need not have an ``#[Id]`` property.
|
||||
only for entity classes inheriting from it. That implies that a
|
||||
mapped superclass cannot be the ``targetEntity`` in associations.
|
||||
|
||||
In other words, a mapped superclass can use unidirectional One-To-One
|
||||
and Many-To-One associations where it is the owning side.
|
||||
Many-To-Many associations are only possible if the mapped
|
||||
superclass is only used in exactly one entity at the moment. For further
|
||||
support of inheritance, the single or joined table inheritance features
|
||||
have to be used.
|
||||
|
||||
.. note::
|
||||
|
||||
A mapped superclass cannot be an entity, it is not query-able and
|
||||
persistent relationships defined by a mapped superclass must be
|
||||
unidirectional (with an owning side only). This means that One-To-Many
|
||||
associations are not possible on a mapped superclass at all.
|
||||
Furthermore Many-To-Many associations are only possible if the
|
||||
mapped superclass is only used in exactly one entity at the moment.
|
||||
For further support of inheritance, the single or
|
||||
joined table inheritance features have to be used.
|
||||
One-To-Many associations are not generally possible on a mapped
|
||||
superclass, since they require the "many" side to hold the foreign
|
||||
key.
|
||||
|
||||
It is, however, possible to use the :doc:`ResolveTargetEntityListener </cookbook/resolve-target-entity-listener>`
|
||||
to replace references to a mapped superclass with an entity class at runtime.
|
||||
As long as there is only one entity subclass inheriting from the mapped
|
||||
superclass and all references to the mapped superclass are resolved to that
|
||||
entity class at runtime, the mapped superclass *can* use One-To-Many associations
|
||||
and be named as the ``targetEntity`` on the owning sides.
|
||||
|
||||
.. warning::
|
||||
|
||||
At least when using attributes or annotations to specify your mapping,
|
||||
it _seems_ as if you could inherit from a base class that is neither
|
||||
it *seems* as if you could inherit from a base class that is neither
|
||||
an entity nor a mapped superclass, but has properties with mapping configuration
|
||||
on them that would also be used in the inheriting class.
|
||||
|
||||
@@ -50,7 +60,7 @@ need not have an ``#[Id]`` property.
|
||||
You may be tempted to use traits to mix mapped fields or relationships
|
||||
into your entity classes to circumvent some of the limitations of
|
||||
mapped superclasses. Before doing that, please read the section on traits
|
||||
in the :doc:`Limitations and Known Issues <reference/limitations-and-known-issues>` chapter.
|
||||
in the :doc:`Limitations and Known Issues </reference/limitations-and-known-issues>` chapter.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -370,7 +380,7 @@ It is not supported to use overrides in entity inheritance scenarios.
|
||||
.. note::
|
||||
|
||||
When using traits, make sure not to miss the warnings given in the
|
||||
:doc:`Limitations and Known Issues<reference/limitations-and-known-issues>` chapter.
|
||||
:doc:`Limitations and Known Issues</reference/limitations-and-known-issues>` chapter.
|
||||
|
||||
|
||||
Association Override
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
The installation chapter has moved to :doc:`Installation and Configuration <reference/configuration>`_.
|
||||
The installation chapter has moved to :doc:`Installation and Configuration </reference/configuration>`.
|
||||
|
||||
@@ -145,7 +145,7 @@ more than two years after the initial Doctrine 2 release and the time where
|
||||
core components were designed.
|
||||
|
||||
In fact, this documentation mentions traits only in the context of
|
||||
:doc:`overriding field association mappings in subclasses <tutorials/override-field-association-mappings-in-subclasses>`.
|
||||
:doc:`overriding field association mappings in subclasses </tutorials/override-field-association-mappings-in-subclasses>`.
|
||||
Coverage of traits in test cases is practically nonexistent.
|
||||
|
||||
Thus, you should at least be aware that when using traits in your entity and
|
||||
@@ -162,14 +162,14 @@ that, some precedence and conflict resolution rules apply.
|
||||
|
||||
When it comes to loading mapping configuration, the annotation and attribute drivers
|
||||
rely on PHP reflection to inspect class properties including their docblocks.
|
||||
As long as the results are consistent with what a solution _without_ traits would
|
||||
As long as the results are consistent with what a solution *without* traits would
|
||||
have produced, this is probably fine.
|
||||
|
||||
However, to mention known limitations, it is currently not possible to use "class"
|
||||
level `annotations <https://github.com/doctrine/orm/pull/1517>` or
|
||||
`attributes <https://github.com/doctrine/orm/issues/8868>` on traits, and attempts to
|
||||
improve parser support for traits as `here <https://github.com/doctrine/annotations/pull/102>`
|
||||
or `there <https://github.com/doctrine/annotations/pull/63>` have been abandoned
|
||||
level `annotations <https://github.com/doctrine/orm/pull/1517>`_ or
|
||||
`attributes <https://github.com/doctrine/orm/issues/8868>`_ on traits, and attempts to
|
||||
improve parser support for traits as `here <https://github.com/doctrine/annotations/pull/102>`_
|
||||
or `there <https://github.com/doctrine/annotations/pull/63>`_ have been abandoned
|
||||
due to complexity.
|
||||
|
||||
XML mapping configuration probably needs to completely re-configure or otherwise
|
||||
|
||||
@@ -123,12 +123,12 @@ the ``FileDriver`` implementation for you to extend from:
|
||||
class MyMetadataDriver extends FileDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected $_fileExtension = '.dcm.ext';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
@@ -138,7 +138,7 @@ the ``FileDriver`` implementation for you to extend from:
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function _loadMappingFile($file)
|
||||
{
|
||||
|
||||
@@ -250,6 +250,40 @@ The first parameter is the name of the column in the SQL result set
|
||||
and the second parameter is the result alias under which the value
|
||||
of the column will be placed in the transformed Doctrine result.
|
||||
|
||||
Special case: DTOs
|
||||
...................
|
||||
|
||||
You can also use ``ResultSetMapping`` to map the results of a native SQL
|
||||
query to a DTO (Data Transfer Object). This is done by adding scalar
|
||||
results for each argument of the DTO's constructor, then filling the
|
||||
``newObjectMappings`` property of the ``ResultSetMapping`` with
|
||||
information about where to map each scalar result:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
$rsm = new ResultSetMapping();
|
||||
$rsm->addScalarResult('name', 1, 'string');
|
||||
$rsm->addScalarResult('email', 2, 'string');
|
||||
$rsm->addScalarResult('city', 3, 'string');
|
||||
$rsm->newObjectMappings['name'] = [
|
||||
'className' => CmsUserDTO::class,
|
||||
'objIndex' => 0, // a result can contain many DTOs, this is the index of the DTO to map to
|
||||
'argIndex' => 0, // each scalar result can be mapped to a different argument of the DTO constructor
|
||||
];
|
||||
$rsm->newObjectMappings['email'] = [
|
||||
'className' => CmsUserDTO::class,
|
||||
'objIndex' => 0,
|
||||
'argIndex' => 1,
|
||||
];
|
||||
$rsm->newObjectMappings['city'] = [
|
||||
'className' => CmsUserDTO::class,
|
||||
'objIndex' => 0,
|
||||
'argIndex' => 2,
|
||||
];
|
||||
|
||||
|
||||
Meta results
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Partial Objects
|
||||
|
||||
Creating Partial Objects through DQL is deprecated and
|
||||
will be removed in the future, use data transfer object
|
||||
support in DQL instead. (`Details
|
||||
support in DQL instead. (\ `Details
|
||||
<https://github.com/doctrine/orm/issues/8471>`_)
|
||||
|
||||
A partial object is an object whose state is not fully initialized
|
||||
|
||||
@@ -167,7 +167,7 @@ The API of the ClassMetadataBuilder has the following methods with a fluent inte
|
||||
- ``addNamedQuery($name, $dqlQuery)``
|
||||
- ``setJoinedTableInheritance()``
|
||||
- ``setSingleTableInheritance()``
|
||||
- ``setDiscriminatorColumn($name, $type = 'string', $length = 255, $columnDefinition = null, $enumType = null)``
|
||||
- ``setDiscriminatorColumn($name, $type = 'string', $length = 255, $columnDefinition = null, $enumType = null, $options = [])``
|
||||
- ``addDiscriminatorMapClass($name, $class)``
|
||||
- ``setChangeTrackingPolicyDeferredExplicit()``
|
||||
- ``setChangeTrackingPolicyNotify()``
|
||||
|
||||
@@ -253,7 +253,7 @@ Calling ``setParameter()`` automatically infers which type you are setting as
|
||||
value. This works for integers, arrays of strings/integers, DateTime instances
|
||||
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 DBAL
|
||||
Doctrine\DBAL\ParameterType::* or a DBAL Type name for conversion.
|
||||
``Doctrine\DBAL\ParameterType::*`` or a DBAL Type name for conversion.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -578,8 +578,6 @@ of DQL. It takes 3 parameters: ``$dqlPartName``, ``$dqlPart`` and
|
||||
not (no effect on the ``where`` and ``having`` DQL query parts,
|
||||
which always override all previously defined items)
|
||||
|
||||
-
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
@@ -322,7 +322,10 @@ level cache region.
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="Country">
|
||||
<cache usage="READ_ONLY" region="my_entity_region" />
|
||||
<id name="id" type="integer" column="id">
|
||||
@@ -427,7 +430,10 @@ It caches the primary keys of association and cache each element will be cached
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="State">
|
||||
|
||||
<cache usage="NONSTRICT_READ_WRITE" />
|
||||
|
||||
@@ -153,7 +153,7 @@ You need to create a class which implements ``Doctrine\ORM\Mapping\TypedFieldMap
|
||||
final class CustomEnumTypedFieldMapper implements TypedFieldMapper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validateAndComplete(array $mapping, ReflectionProperty $field): array
|
||||
{
|
||||
|
||||
@@ -37,8 +37,8 @@ will still end up with the same reference:
|
||||
public function testIdentityMapReference(): void
|
||||
{
|
||||
$objectA = $this->entityManager->getReference('EntityName', 1);
|
||||
// check for proxyinterface
|
||||
$this->assertInstanceOf('Doctrine\Persistence\Proxy', $objectA);
|
||||
// check entity is not initialized
|
||||
$this->assertTrue($this->entityManager->isUninitializedObject($objectA));
|
||||
|
||||
$objectB = $this->entityManager->find('EntityName', 1);
|
||||
|
||||
@@ -137,7 +137,7 @@ optimize the performance of the Flush Operation:
|
||||
.. note::
|
||||
|
||||
Flush only a single entity with ``$entityManager->flush($entity)`` is deprecated and will be removed in ORM 3.0.
|
||||
(`Details <https://github.com/doctrine/orm/issues/8459>`_)
|
||||
(\ `Details <https://github.com/doctrine/orm/issues/8459>`_)
|
||||
|
||||
Query Internals
|
||||
---------------
|
||||
|
||||
@@ -718,6 +718,7 @@ methods:
|
||||
|
||||
* ``andX($arg1, $arg2, ...)``
|
||||
* ``orX($arg1, $arg2, ...)``
|
||||
* ``not($expression)``
|
||||
* ``eq($field, $value)``
|
||||
* ``gt($field, $value)``
|
||||
* ``lt($field, $value)``
|
||||
|
||||
@@ -192,6 +192,11 @@ be properly synchronized with the database when
|
||||
database in the most efficient way and a single, short transaction,
|
||||
taking care of maintaining referential integrity.
|
||||
|
||||
.. note::
|
||||
|
||||
Do not make any assumptions in your code about the number of queries
|
||||
it takes to flush changes, about the ordering of ``INSERT``, ``UPDATE``
|
||||
and ``DELETE`` queries or the order in which entities will be processed.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -286,17 +291,53 @@ as follows:
|
||||
After an entity has been removed, its in-memory state is the same as
|
||||
before the removal, except for generated identifiers.
|
||||
|
||||
Removing an entity will also automatically delete any existing
|
||||
records in many-to-many join tables that link this entity. The
|
||||
action taken depends on the value of the ``@joinColumn`` mapping
|
||||
attribute "onDelete". Either Doctrine issues a dedicated ``DELETE``
|
||||
statement for records of each join table or it depends on the
|
||||
foreign key semantics of onDelete="CASCADE".
|
||||
During the ``EntityManager#flush()`` operation, the removed entity
|
||||
will also be removed from all collections in entities currently
|
||||
loaded into memory.
|
||||
|
||||
.. _remove_object_many_to_many_join_tables:
|
||||
|
||||
Join-table management when removing from many-to-many collections
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Regarding existing rows in many-to-many join tables that refer to
|
||||
an entity being removed, the following applies.
|
||||
|
||||
When the entity being removed does not declare the many-to-many association
|
||||
itself (that is, the many-to-many association is unidirectional and
|
||||
the entity is on the inverse side), the ORM has no reasonable way to
|
||||
detect associations targeting the entity's class. Thus, no ORM-level handling
|
||||
of join-table rows is attempted and database-level constraints apply.
|
||||
In case of database-level ``ON DELETE RESTRICT`` constraints, the
|
||||
``EntityManager#flush()`` operation may abort and a ``ConstraintViolationException``
|
||||
may be thrown. No in-memory collections will be modified in this case.
|
||||
With ``ON DELETE CASCADE``, the RDBMS will take care of removing rows
|
||||
from join tables.
|
||||
|
||||
When the entity being removed is part of bi-directional many-to-many
|
||||
association, either as the owning or inverse side, the ORM will
|
||||
delete rows from join tables before removing the entity itself. That means
|
||||
database-level ``ON DELETE RESTRICT`` constraints on join tables are not
|
||||
effective, since the join table rows are removed first. Removal of join table
|
||||
rows happens through specialized methods in entity and collection persister
|
||||
classes and take one query per entity and join table. In case the association
|
||||
uses a ``@JoinColumn`` configuration with ``onDelete="CASCADE"``, instead
|
||||
of using a dedicated ``DELETE`` query the database-level operation will be
|
||||
relied upon.
|
||||
|
||||
.. note::
|
||||
|
||||
In case you rely on database-level ``ON DELETE RESTRICT`` constraints,
|
||||
be aware that by making many-to-many associations bidirectional the
|
||||
assumed protection may be lost.
|
||||
|
||||
|
||||
Performance of different deletion strategies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Deleting an object with all its associated objects can be achieved
|
||||
in multiple ways with very different performance impacts.
|
||||
|
||||
|
||||
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM
|
||||
will fetch this association. If its a Single association it will
|
||||
pass this entity to
|
||||
|
||||
@@ -16,9 +16,9 @@ setup for the latest code in trunk.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
...
|
||||
@@ -102,9 +102,9 @@ of several common elements:
|
||||
|
||||
// Doctrine.Tests.ORM.Mapping.User.dcm.xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\ORM\Mapping\User" table="cms_users">
|
||||
@@ -769,9 +769,9 @@ entity relationship. You can define this in XML with the "association-key" attri
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Application\Model\ArticleAttribute">
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
Welcome to Doctrine 2 ORM's documentation!
|
||||
==========================================
|
||||
|
||||
Tutorials
|
||||
---------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
tutorials/getting-started
|
||||
tutorials/getting-started-database
|
||||
tutorials/getting-started-models
|
||||
tutorials/working-with-indexed-associations
|
||||
tutorials/extra-lazy-associations
|
||||
tutorials/composite-primary-keys
|
||||
tutorials/ordered-associations
|
||||
tutorials/override-field-association-mappings-in-subclasses
|
||||
tutorials/pagination.rst
|
||||
tutorials/embeddables.rst
|
||||
|
||||
Reference Guide
|
||||
---------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:numbered:
|
||||
|
||||
reference/architecture
|
||||
reference/configuration.rst
|
||||
reference/faq
|
||||
reference/basic-mapping
|
||||
reference/association-mapping
|
||||
reference/inheritance-mapping
|
||||
reference/working-with-objects
|
||||
reference/working-with-associations
|
||||
reference/events
|
||||
reference/unitofwork
|
||||
reference/unitofwork-associations
|
||||
reference/transactions-and-concurrency
|
||||
reference/batch-processing
|
||||
reference/dql-doctrine-query-language
|
||||
reference/query-builder
|
||||
reference/native-sql
|
||||
reference/change-tracking-policies
|
||||
reference/partial-objects
|
||||
reference/annotations-reference
|
||||
reference/attributes-reference
|
||||
reference/xml-mapping
|
||||
reference/yaml-mapping
|
||||
reference/php-mapping
|
||||
reference/caching
|
||||
reference/improving-performance
|
||||
reference/tools
|
||||
reference/metadata-drivers
|
||||
reference/best-practices
|
||||
reference/limitations-and-known-issues
|
||||
tutorials/pagination
|
||||
reference/filters
|
||||
reference/namingstrategy
|
||||
reference/advanced-configuration
|
||||
reference/second-level-cache
|
||||
reference/security
|
||||
|
||||
|
||||
Cookbook
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
cookbook/aggregate-fields
|
||||
cookbook/custom-mapping-types
|
||||
cookbook/decorator-pattern
|
||||
cookbook/dql-custom-walkers
|
||||
cookbook/dql-user-defined-functions
|
||||
cookbook/implementing-arrayaccess-for-domain-objects
|
||||
cookbook/implementing-the-notify-changetracking-policy
|
||||
cookbook/resolve-target-entity-listener
|
||||
cookbook/sql-table-prefixes
|
||||
cookbook/strategy-cookbook-introduction
|
||||
cookbook/validation-of-entities
|
||||
cookbook/working-with-datetime
|
||||
cookbook/mysql-enums
|
||||
cookbook/advanced-field-value-conversion-using-custom-mapping-types
|
||||
cookbook/entities-in-session
|
||||
|
||||
@@ -85,9 +85,9 @@ and year of production as primary keys:
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="VehicleCatalogue\Model\Car">
|
||||
@@ -267,9 +267,9 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Application\Model\ArticleAttribute">
|
||||
|
||||
@@ -85,9 +85,9 @@ switch to extra lazy as shown in these examples:
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\CMS\CmsGroup">
|
||||
|
||||
@@ -22,5 +22,5 @@ In this workflow you would modify the database schema first and then
|
||||
regenerate the PHP code to use with this schema. You need a flexible
|
||||
code-generator for this task.
|
||||
|
||||
We spinned off a subproject, Doctrine CodeGenerator, that will fill this gap and
|
||||
We spun off a subproject, Doctrine CodeGenerator, that will fill this gap and
|
||||
allow you to do *Database First* development.
|
||||
|
||||
@@ -18,7 +18,7 @@ before. There are some prerequisites for the tutorial that have to be
|
||||
installed:
|
||||
|
||||
- PHP (latest stable version)
|
||||
- Composer Package Manager (`Install Composer
|
||||
- Composer Package Manager (\ `Install Composer
|
||||
<https://getcomposer.org/doc/00-intro.md>`_)
|
||||
|
||||
The code of this tutorial is `available on Github <https://github.com/doctrine/doctrine2-orm-tutorial>`_.
|
||||
@@ -102,8 +102,7 @@ Install Doctrine using the Composer Dependency Management tool, by calling:
|
||||
This will install the packages Doctrine Common, Doctrine DBAL, Doctrine ORM,
|
||||
into the ``vendor`` directory.
|
||||
|
||||
Add the following directories:
|
||||
::
|
||||
Add the following directories::
|
||||
|
||||
doctrine2-tutorial
|
||||
|-- config
|
||||
@@ -322,7 +321,7 @@ data in your storage, and later in your application when the data is loaded agai
|
||||
.. note::
|
||||
|
||||
This method, although very common, is inappropriate for Domain Driven
|
||||
Design (`DDD <https://en.wikipedia.org/wiki/Domain-driven_design>`)
|
||||
Design (\ `DDD <https://en.wikipedia.org/wiki/Domain-driven_design>`_)
|
||||
where methods should represent real business operations and not simple
|
||||
property change, And business invariants should be maintained both in the
|
||||
application state (entities in this case) and in the database, with no
|
||||
@@ -449,7 +448,7 @@ entity.
|
||||
|
||||
.. note::
|
||||
|
||||
A `DTO <https://en.wikipedia.org/wiki/Data_transfer_object>` is an object
|
||||
A `DTO <https://en.wikipedia.org/wiki/Data_transfer_object>`_ is an object
|
||||
that only carries data without any logic. Its only goal is to be transferred
|
||||
from one service to another.
|
||||
A ``DTO`` often represents data sent by a client and that has to be validated,
|
||||
@@ -558,10 +557,10 @@ methods, but you only need to choose one.
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/Product.dcm.xml -->
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Product" table="products">
|
||||
<id name="id" type="integer">
|
||||
@@ -736,7 +735,7 @@ classes. We'll store them in ``src/Bug.php`` and ``src/User.php``, respectively.
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
#[ORM\GeneratedValue]
|
||||
private int $id;
|
||||
private int|null $id;
|
||||
|
||||
#[ORM\Column(type: 'string')]
|
||||
private string $description;
|
||||
@@ -1139,10 +1138,10 @@ the ``Product`` before:
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/Bug.dcm.xml -->
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Bug" table="bugs">
|
||||
<id name="id" type="integer">
|
||||
@@ -1200,21 +1199,21 @@ which translates the YYYY-mm-dd HH:mm:ss database format
|
||||
into a PHP DateTime instance and back.
|
||||
|
||||
After the field definitions, the two qualified references to the
|
||||
user entity are defined. They are created by the ``many-to-one``
|
||||
tag. The class name of the related entity has to be specified with
|
||||
the ``target-entity`` attribute, which is enough information for
|
||||
the database mapper to access the foreign-table. Since
|
||||
user entity are defined. They are created by the ``ManyToOne``
|
||||
attribute. The class name of the related entity has to be specified with
|
||||
the ``targetEntity`` parameter, which is enough information for
|
||||
the database mapper to access the foreign table. Since
|
||||
``reporter`` and ``engineer`` are on the owning side of a
|
||||
bi-directional relation, we also have to specify the ``inversed-by``
|
||||
attribute. They have to point to the field names on the inverse
|
||||
side of the relationship. We will see in the next example that the ``inversed-by``
|
||||
attribute has a counterpart ``mapped-by`` which makes that
|
||||
bi-directional relation, we also have to specify the ``inversedBy``
|
||||
parameter. They have to point to the field names on the inverse
|
||||
side of the relationship. We will see in the next example that the ``inversedBy``
|
||||
parameter has a counterpart ``mappedBy`` which makes that
|
||||
the inverse side.
|
||||
|
||||
The last definition is for the ``Bug#products`` collection. It
|
||||
holds all products where the specific bug occurs. Again
|
||||
you have to define the ``target-entity`` and ``field`` attributes
|
||||
on the ``many-to-many`` tag.
|
||||
you have to define the ``targetEntity`` and ``field`` parameters
|
||||
on the ``ManyToMany`` attribute.
|
||||
|
||||
Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
|
||||
@@ -1294,10 +1293,10 @@ Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/User.dcm.xml -->
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="User" table="users">
|
||||
<id name="id" type="integer">
|
||||
@@ -1337,15 +1336,14 @@ Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
targetEntity: Bug
|
||||
mappedBy: engineer
|
||||
|
||||
Here are some new things to mention about the ``one-to-many`` tags.
|
||||
Here are some new things to mention about the ``OneToMany`` attribute.
|
||||
Remember that we discussed about the inverse and owning side. Now
|
||||
both reportedBugs and assignedBugs are inverse relations, which
|
||||
means the join details have already been defined on the owning
|
||||
side. Therefore we only have to specify the property on the Bug
|
||||
class that holds the owning sides.
|
||||
|
||||
Update your database schema by running:
|
||||
::
|
||||
Update your database schema by running::
|
||||
|
||||
$ php bin/doctrine orm:schema-tool:update --force
|
||||
|
||||
@@ -1819,9 +1817,9 @@ we have to adjust the metadata slightly.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Bug" table="bugs" repository-class="BugRepository">
|
||||
|
||||
@@ -15,7 +15,7 @@ has a very simple API and implements the SPL interfaces ``Countable`` and
|
||||
->setFirstResult(0)
|
||||
->setMaxResults(100);
|
||||
|
||||
$paginator = new Paginator($query, $fetchJoinCollection = true);
|
||||
$paginator = new Paginator($query, fetchJoinCollection: true);
|
||||
|
||||
$c = count($paginator);
|
||||
foreach ($paginator as $post) {
|
||||
@@ -36,10 +36,10 @@ correct result:
|
||||
|
||||
This behavior is only necessary if you actually fetch join a to-many
|
||||
collection. You can disable this behavior by setting the
|
||||
``$fetchJoinCollection`` flag to ``false``; in that case only 2 instead of the 3 queries
|
||||
``fetchJoinCollection`` argument to ``false``; in that case only 2 instead of the 3 queries
|
||||
described are executed. We hope to automate the detection for this in
|
||||
the future.
|
||||
|
||||
.. note::
|
||||
|
||||
``$fetchJoinCollection`` flag set to ``true`` might affect results if you use aggregations in your query.
|
||||
``fetchJoinCollection`` argument set to ``true`` might affect results if you use aggregations in your query.
|
||||
|
||||
@@ -161,9 +161,9 @@ The code and mappings for the Market entity looks like this:
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\StockExchange\Market">
|
||||
@@ -278,9 +278,9 @@ here are the code and mappings for it:
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\StockExchange\Stock">
|
||||
|
||||
@@ -302,7 +302,7 @@
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
|
||||
<xs:attribute name="type" type="orm:type" default="string" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="unique" type="xs:boolean" default="false" />
|
||||
@@ -330,6 +330,7 @@
|
||||
|
||||
<xs:complexType name="discriminator-column">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
@@ -414,7 +415,7 @@
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="type" type="orm:type" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="association-key" type="xs:boolean" default="false" />
|
||||
@@ -446,6 +447,13 @@
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="type" id="type">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:pattern value="([a-zA-Z_u01-uff][a-zA-Z0-9_u01-uff]+)|(\c+)" id="type.class.pattern">
|
||||
</xs:pattern>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="inverse-join-columns">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />
|
||||
@@ -630,7 +638,7 @@
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
|
||||
<xs:attribute name="type" type="orm:type" default="string" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="unique" type="xs:boolean" default="false" />
|
||||
|
||||
@@ -1010,7 +1010,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* Alias for getSingleResult(HYDRATE_SINGLE_SCALAR).
|
||||
*
|
||||
* @return mixed The scalar result.
|
||||
* @return bool|float|int|string|null The scalar result.
|
||||
*
|
||||
* @throws NoResultException If the query returned no result.
|
||||
* @throws NonUniqueResultException If the query result is not unique.
|
||||
|
||||
@@ -14,6 +14,8 @@ use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
|
||||
/**
|
||||
* Contract for building second level cache regions components.
|
||||
*
|
||||
* @psalm-import-type AssociationMapping from ClassMetadata
|
||||
*/
|
||||
interface CacheFactory
|
||||
{
|
||||
@@ -31,7 +33,7 @@ interface CacheFactory
|
||||
/**
|
||||
* Build a collection persister for the given relation mapping.
|
||||
*
|
||||
* @param mixed[] $mapping The association mapping.
|
||||
* @param AssociationMapping $mapping The association mapping.
|
||||
*
|
||||
* @return CachedCollectionPersister
|
||||
*/
|
||||
|
||||
@@ -48,7 +48,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getEntityCacheRegion($className)
|
||||
{
|
||||
@@ -63,7 +63,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getCollectionCacheRegion($className, $association)
|
||||
{
|
||||
@@ -78,7 +78,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function containsEntity($className, $identifier)
|
||||
{
|
||||
@@ -93,7 +93,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictEntity($className, $identifier)
|
||||
{
|
||||
@@ -108,7 +108,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictEntityRegion($className)
|
||||
{
|
||||
@@ -123,7 +123,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictEntityRegions()
|
||||
{
|
||||
@@ -141,7 +141,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function containsCollection($className, $association, $ownerIdentifier)
|
||||
{
|
||||
@@ -156,7 +156,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictCollection($className, $association, $ownerIdentifier)
|
||||
{
|
||||
@@ -171,7 +171,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictCollectionRegion($className, $association)
|
||||
{
|
||||
@@ -186,7 +186,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictCollectionRegions()
|
||||
{
|
||||
@@ -210,7 +210,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function containsQuery($regionName)
|
||||
{
|
||||
@@ -218,7 +218,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictQueryRegion($regionName = null)
|
||||
{
|
||||
@@ -234,7 +234,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictQueryRegions()
|
||||
{
|
||||
@@ -246,7 +246,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getQueryCache($regionName = null)
|
||||
{
|
||||
|
||||
@@ -106,7 +106,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata)
|
||||
{
|
||||
@@ -134,10 +134,11 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildCachedCollectionPersister(EntityManagerInterface $em, CollectionPersister $persister, array $mapping)
|
||||
{
|
||||
assert(isset($mapping['cache']));
|
||||
$usage = $mapping['cache']['usage'];
|
||||
$region = $this->getRegion($mapping['cache']);
|
||||
|
||||
@@ -161,7 +162,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildQueryCache(EntityManagerInterface $em, $regionName = null)
|
||||
{
|
||||
@@ -177,7 +178,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildCollectionHydrator(EntityManagerInterface $em, array $mapping)
|
||||
{
|
||||
@@ -185,7 +186,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata)
|
||||
{
|
||||
@@ -193,7 +194,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getRegion(array $cache)
|
||||
{
|
||||
@@ -224,7 +225,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getTimestampRegion()
|
||||
{
|
||||
@@ -239,7 +240,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createCache(EntityManagerInterface $entityManager)
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, $collection)
|
||||
{
|
||||
@@ -49,7 +49,7 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection)
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, $entity)
|
||||
{
|
||||
@@ -140,7 +140,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, EntityCacheEntry $entry, $entity = null)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,6 @@ use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\Persistence\Proxy;
|
||||
|
||||
use function array_map;
|
||||
use function array_shift;
|
||||
@@ -29,6 +28,8 @@ use function reset;
|
||||
|
||||
/**
|
||||
* Default query cache implementation.
|
||||
*
|
||||
* @psalm-import-type AssociationMapping from ClassMetadata
|
||||
*/
|
||||
class DefaultQueryCache implements QueryCache
|
||||
{
|
||||
@@ -66,7 +67,7 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = [])
|
||||
{
|
||||
@@ -225,7 +226,7 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function put(QueryCacheKey $key, ResultSetMapping $rsm, $result, array $hints = [])
|
||||
{
|
||||
@@ -326,8 +327,8 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $assoc
|
||||
* @param mixed $assocValue
|
||||
* @param AssociationMapping $assoc
|
||||
* @param mixed $assocValue
|
||||
*
|
||||
* @return mixed[]|null
|
||||
* @psalm-return array{targetEntity: class-string, type: mixed, list?: array[], identifier?: array}|null
|
||||
@@ -343,7 +344,7 @@ class DefaultQueryCache implements QueryCache
|
||||
$assocIdentifier = $this->uow->getEntityIdentifier($assocValue);
|
||||
$entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier);
|
||||
|
||||
if (! $assocValue instanceof Proxy && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
|
||||
if (! $this->uow->isUninitializedObject($assocValue) && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
|
||||
// Entity put fail
|
||||
if (! $assocPersister->storeEntityCache($assocValue, $entityKey)) {
|
||||
return null;
|
||||
@@ -448,7 +449,7 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
@@ -456,7 +457,7 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getRegion()
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCacheHit($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -50,7 +50,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCacheMiss($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -60,7 +60,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCachePut($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -70,7 +70,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCacheHit($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -80,7 +80,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCacheMiss($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -90,7 +90,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCachePut($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -100,7 +100,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCacheHit($regionName, QueryCacheKey $key)
|
||||
{
|
||||
@@ -110,7 +110,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCacheMiss($regionName, QueryCacheKey $key)
|
||||
{
|
||||
@@ -120,7 +120,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCachePut($regionName, QueryCacheKey $key)
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
private $cachePutCountMap = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCacheMiss($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -34,7 +34,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCacheHit($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -43,7 +43,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCachePut($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -52,7 +52,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCacheMiss($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -61,7 +61,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCacheHit($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -70,7 +70,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCachePut($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -79,7 +79,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCacheHit($regionName, QueryCacheKey $key)
|
||||
{
|
||||
@@ -88,7 +88,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCacheMiss($regionName, QueryCacheKey $key)
|
||||
{
|
||||
@@ -97,7 +97,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCachePut($regionName, QueryCacheKey $key)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@ use function array_values;
|
||||
use function assert;
|
||||
use function count;
|
||||
|
||||
/** @psalm-import-type AssociationMapping from ClassMetadata */
|
||||
abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
{
|
||||
/** @var UnitOfWork */
|
||||
@@ -64,7 +65,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
* @param CollectionPersister $persister The collection persister that will be cached.
|
||||
* @param Region $region The collection region.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param mixed[] $association The association mapping.
|
||||
* @param AssociationMapping $association The association mapping.
|
||||
*/
|
||||
public function __construct(CollectionPersister $persister, Region $region, EntityManagerInterface $em, array $association)
|
||||
{
|
||||
@@ -85,7 +86,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getCacheRegion()
|
||||
{
|
||||
@@ -93,7 +94,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSourceEntityMetadata()
|
||||
{
|
||||
@@ -101,7 +102,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getTargetEntityMetadata()
|
||||
{
|
||||
@@ -109,7 +110,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -123,7 +124,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function storeCollectionCache(CollectionCacheKey $key, $elements)
|
||||
{
|
||||
@@ -167,7 +168,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function contains(PersistentCollection $collection, $element)
|
||||
{
|
||||
@@ -175,7 +176,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function containsKey(PersistentCollection $collection, $key)
|
||||
{
|
||||
@@ -183,7 +184,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function count(PersistentCollection $collection)
|
||||
{
|
||||
@@ -199,7 +200,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get(PersistentCollection $collection, $index)
|
||||
{
|
||||
@@ -207,7 +208,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function slice(PersistentCollection $collection, $offset, $length = null)
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ use function spl_object_id;
|
||||
class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionComplete()
|
||||
{
|
||||
@@ -32,7 +32,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionRolledBack()
|
||||
{
|
||||
@@ -40,7 +40,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete(PersistentCollection $collection)
|
||||
{
|
||||
@@ -53,7 +53,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update(PersistentCollection $collection)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ use Doctrine\ORM\PersistentCollection;
|
||||
class ReadOnlyCachedCollectionPersister extends NonStrictReadWriteCachedCollectionPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update(PersistentCollection $collection)
|
||||
{
|
||||
|
||||
@@ -7,21 +7,23 @@ namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\ConcurrentRegion;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
|
||||
use function spl_object_id;
|
||||
|
||||
/** @psalm-import-type AssociationMapping from ClassMetadata */
|
||||
class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
{
|
||||
/** @param mixed[] $association The association mapping. */
|
||||
/** @param AssociationMapping $association The association mapping. */
|
||||
public function __construct(CollectionPersister $persister, ConcurrentRegion $region, EntityManagerInterface $em, array $association)
|
||||
{
|
||||
parent::__construct($persister, $region, $em, $association);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionComplete()
|
||||
{
|
||||
@@ -41,7 +43,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionRolledBack()
|
||||
{
|
||||
@@ -61,7 +63,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete(PersistentCollection $collection)
|
||||
{
|
||||
@@ -82,7 +84,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update(PersistentCollection $collection)
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function array_merge;
|
||||
use function assert;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
@@ -98,7 +99,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function addInsert($entity)
|
||||
{
|
||||
@@ -106,7 +107,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getInserts()
|
||||
{
|
||||
@@ -114,7 +115,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, ?array $orderBy = null)
|
||||
{
|
||||
@@ -130,7 +131,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getInsertSQL()
|
||||
{
|
||||
@@ -138,7 +139,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getResultSetMapping()
|
||||
{
|
||||
@@ -146,7 +147,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSelectConditionStatementSQL($field, $value, $assoc = null, $comparison = null)
|
||||
{
|
||||
@@ -154,7 +155,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function exists($entity, ?Criteria $extraConditions = null)
|
||||
{
|
||||
@@ -170,7 +171,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getCacheRegion()
|
||||
{
|
||||
@@ -184,7 +185,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function storeEntityCache($entity, EntityCacheKey $key)
|
||||
{
|
||||
@@ -262,7 +263,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function expandParameters($criteria)
|
||||
{
|
||||
@@ -270,7 +271,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function expandCriteriaParameters(Criteria $criteria)
|
||||
{
|
||||
@@ -278,7 +279,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassMetadata()
|
||||
{
|
||||
@@ -286,7 +287,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||
{
|
||||
@@ -294,7 +295,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||
{
|
||||
@@ -302,7 +303,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getOwningTable($fieldName)
|
||||
{
|
||||
@@ -310,17 +311,23 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function executeInserts()
|
||||
{
|
||||
$this->queuedCache['insert'] = $this->persister->getInserts();
|
||||
// The commit order/foreign key relationships may make it necessary that multiple calls to executeInsert()
|
||||
// are performed, so collect all the new entities.
|
||||
$newInserts = $this->persister->getInserts();
|
||||
|
||||
if ($newInserts) {
|
||||
$this->queuedCache['insert'] = array_merge($this->queuedCache['insert'] ?? [], $newInserts);
|
||||
}
|
||||
|
||||
return $this->persister->executeInserts();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function load(array $criteria, $entity = null, $assoc = null, array $hints = [], $lockMode = null, $limit = null, ?array $orderBy = null)
|
||||
{
|
||||
@@ -364,7 +371,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadAll(array $criteria = [], ?array $orderBy = null, $limit = null, $offset = null)
|
||||
{
|
||||
@@ -400,7 +407,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadById(array $identifier, $entity = null)
|
||||
{
|
||||
@@ -464,7 +471,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadCriteria(Criteria $criteria)
|
||||
{
|
||||
@@ -503,7 +510,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
|
||||
{
|
||||
@@ -538,7 +545,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
|
||||
{
|
||||
@@ -573,7 +580,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadOneToOneEntity(array $assoc, $sourceEntity, array $identifier = [])
|
||||
{
|
||||
@@ -581,7 +588,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function lock(array $criteria, $lockMode)
|
||||
{
|
||||
@@ -589,7 +596,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function refresh(array $id, $entity, $lockMode = null)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ use function get_class;
|
||||
class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionComplete()
|
||||
{
|
||||
@@ -48,7 +48,7 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionRolledBack()
|
||||
{
|
||||
@@ -56,7 +56,7 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($entity)
|
||||
{
|
||||
@@ -73,7 +73,7 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($entity)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyEntity;
|
||||
class ReadOnlyCachedEntityPersister extends NonStrictReadWriteCachedEntityPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($entity)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionComplete()
|
||||
{
|
||||
@@ -51,7 +51,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionRolledBack()
|
||||
{
|
||||
@@ -71,7 +71,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($entity)
|
||||
{
|
||||
@@ -96,7 +96,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($entity)
|
||||
{
|
||||
|
||||
@@ -91,7 +91,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
@@ -109,7 +109,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function contains(CacheKey $key)
|
||||
{
|
||||
@@ -117,7 +117,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get(CacheKey $key)
|
||||
{
|
||||
@@ -132,7 +132,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMultiple(CollectionCacheEntry $collection)
|
||||
{
|
||||
@@ -164,7 +164,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -182,7 +182,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -192,7 +192,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -116,7 +116,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
@@ -124,7 +124,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function contains(CacheKey $key)
|
||||
{
|
||||
@@ -136,7 +136,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get(CacheKey $key)
|
||||
{
|
||||
@@ -148,7 +148,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMultiple(CollectionCacheEntry $collection)
|
||||
{
|
||||
@@ -160,7 +160,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function put(CacheKey $key, CacheEntry $entry, ?Lock $lock = null)
|
||||
{
|
||||
@@ -172,7 +172,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evict(CacheKey $key)
|
||||
{
|
||||
@@ -184,7 +184,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictAll()
|
||||
{
|
||||
@@ -202,7 +202,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function lock(CacheKey $key)
|
||||
{
|
||||
@@ -223,7 +223,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function unlock(CacheKey $key, Lock $lock)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ use Doctrine\ORM\Cache\TimestampRegion;
|
||||
class UpdateTimestampCache extends DefaultRegion implements TimestampRegion
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update(CacheKey $key)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ class TimestampQueryCacheValidator implements QueryCacheValidator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isValid(QueryCacheKey $key, QueryCacheEntry $entry)
|
||||
{
|
||||
|
||||
@@ -62,8 +62,6 @@ use function trim;
|
||||
* It combines all configuration options from DBAL & ORM.
|
||||
*
|
||||
* Internal note: When adding a new configuration option just write a getter/setter pair.
|
||||
*
|
||||
* @psalm-import-type AutogenerateMode from ProxyFactory
|
||||
*/
|
||||
class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
@@ -95,8 +93,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the strategy for automatically generating proxy classes.
|
||||
*
|
||||
* @return int Possible values are constants of Doctrine\ORM\Proxy\ProxyFactory.
|
||||
* @psalm-return AutogenerateMode
|
||||
* @return ProxyFactory::AUTOGENERATE_*
|
||||
*/
|
||||
public function getAutoGenerateProxyClasses()
|
||||
{
|
||||
@@ -106,9 +103,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets the strategy for automatically generating proxy classes.
|
||||
*
|
||||
* @param bool|int $autoGenerate Possible values are constants of Doctrine\ORM\Proxy\ProxyFactory.
|
||||
* @psalm-param bool|AutogenerateMode $autoGenerate
|
||||
* True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
|
||||
* @param bool|ProxyFactory::AUTOGENERATE_* $autoGenerate True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -164,7 +159,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @return AnnotationDriver
|
||||
*/
|
||||
public function newDefaultAnnotationDriver($paths = [], $useSimpleAnnotationReader = true)
|
||||
public function newDefaultAnnotationDriver($paths = [], $useSimpleAnnotationReader = true, bool $reportFieldsWhereDeclared = false)
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -203,15 +198,16 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
|
||||
return new AnnotationDriver(
|
||||
$reader,
|
||||
(array) $paths
|
||||
(array) $paths,
|
||||
$reportFieldsWhereDeclared
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated No replacement planned.
|
||||
*
|
||||
* Adds a namespace under a certain alias.
|
||||
*
|
||||
* @deprecated No replacement planned.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param string $namespace
|
||||
*
|
||||
@@ -1121,4 +1117,14 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
|
||||
$this->_attributes['isLazyGhostObjectEnabled'] = $flag;
|
||||
}
|
||||
|
||||
public function setRejectIdCollisionInIdentityMap(bool $flag): void
|
||||
{
|
||||
$this->_attributes['rejectIdCollisionInIdentityMap'] = $flag;
|
||||
}
|
||||
|
||||
public function isRejectIdCollisionInIdentityMapEnabled(): bool
|
||||
{
|
||||
return $this->_attributes['rejectIdCollisionInIdentityMap'] ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
@@ -39,7 +39,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getExpressionBuilder()
|
||||
{
|
||||
@@ -47,7 +47,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
*
|
||||
@@ -61,7 +61,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassMetadata($className)
|
||||
{
|
||||
@@ -69,7 +69,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function beginTransaction()
|
||||
{
|
||||
@@ -77,7 +77,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function transactional($func)
|
||||
{
|
||||
@@ -85,7 +85,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function wrapInTransaction(callable $func)
|
||||
{
|
||||
@@ -102,7 +102,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
@@ -110,7 +110,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
@@ -118,7 +118,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createQuery($dql = '')
|
||||
{
|
||||
@@ -126,7 +126,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createNamedQuery($name)
|
||||
{
|
||||
@@ -134,7 +134,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createNativeQuery($sql, ResultSetMapping $rsm)
|
||||
{
|
||||
@@ -142,7 +142,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createNamedNativeQuery($name)
|
||||
{
|
||||
@@ -150,7 +150,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createQueryBuilder()
|
||||
{
|
||||
@@ -158,7 +158,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReference($entityName, $id)
|
||||
{
|
||||
@@ -166,7 +166,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPartialReference($entityName, $identifier)
|
||||
{
|
||||
@@ -174,7 +174,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
@@ -182,7 +182,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function copy($entity, $deep = false)
|
||||
{
|
||||
@@ -190,7 +190,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function lock($entity, $lockMode, $lockVersion = null)
|
||||
{
|
||||
@@ -198,7 +198,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($className, $id, $lockMode = null, $lockVersion = null)
|
||||
{
|
||||
@@ -206,7 +206,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function flush($entity = null)
|
||||
{
|
||||
@@ -214,7 +214,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function refresh($object)
|
||||
{
|
||||
@@ -228,7 +228,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getEventManager()
|
||||
{
|
||||
@@ -236,7 +236,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getConfiguration()
|
||||
{
|
||||
@@ -244,7 +244,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isOpen()
|
||||
{
|
||||
@@ -252,7 +252,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getUnitOfWork()
|
||||
{
|
||||
@@ -260,7 +260,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getHydrator($hydrationMode)
|
||||
{
|
||||
@@ -268,7 +268,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function newHydrator($hydrationMode)
|
||||
{
|
||||
@@ -276,7 +276,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getProxyFactory()
|
||||
{
|
||||
@@ -284,7 +284,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
@@ -292,7 +292,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isFiltersStateClean()
|
||||
{
|
||||
@@ -300,7 +300,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function hasFilters()
|
||||
{
|
||||
@@ -308,7 +308,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getCache()
|
||||
{
|
||||
|
||||
@@ -953,6 +953,14 @@ class EntityManager implements EntityManagerInterface
|
||||
$this->unitOfWork->initializeObject($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isUninitializedObject($obj): bool
|
||||
{
|
||||
return $this->unitOfWork->isUninitializedObject($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create EntityManager instances.
|
||||
*
|
||||
|
||||
@@ -27,7 +27,7 @@ use Doctrine\Persistence\ObjectManager;
|
||||
interface EntityManagerInterface extends ObjectManager
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
*
|
||||
|
||||
@@ -297,7 +297,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassName()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Exception;
|
||||
|
||||
use function get_class;
|
||||
use function sprintf;
|
||||
|
||||
final class EntityIdentityCollisionException extends ORMException
|
||||
{
|
||||
/**
|
||||
* @param object $existingEntity
|
||||
* @param object $newEntity
|
||||
*/
|
||||
public static function create($existingEntity, $newEntity, string $idHash): self
|
||||
{
|
||||
return new self(
|
||||
sprintf(
|
||||
<<<'EXCEPTION'
|
||||
While adding an entity of class %s with an ID hash of "%s" to the identity map,
|
||||
another object of class %s was already present for the same ID. This exception
|
||||
is a safeguard against an internal inconsistency - IDs should uniquely map to
|
||||
entity object instances. This problem may occur if:
|
||||
|
||||
- you use application-provided IDs and reuse ID values;
|
||||
- database-provided IDs are reassigned after truncating the database without
|
||||
clearing the EntityManager;
|
||||
- you might have been using EntityManager#getReference() to create a reference
|
||||
for a nonexistent ID that was subsequently (by the RDBMS) assigned to another
|
||||
entity.
|
||||
|
||||
Otherwise, it might be an ORM-internal inconsistency, please report it.
|
||||
EXCEPTION
|
||||
,
|
||||
get_class($newEntity),
|
||||
$idHash,
|
||||
get_class($existingEntity)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ class AssignedGenerator extends AbstractIdGenerator
|
||||
/**
|
||||
* Returns the identifier assigned to the given entity.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws EntityMissingAssignedId
|
||||
*/
|
||||
|
||||
@@ -49,7 +49,7 @@ class IdentityGenerator extends AbstractIdGenerator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isPostInsertGenerator()
|
||||
{
|
||||
|
||||
@@ -21,20 +21,20 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_allocationSize;
|
||||
private $allocationSize;
|
||||
|
||||
/**
|
||||
* The name of the sequence.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_sequenceName;
|
||||
private $sequenceName;
|
||||
|
||||
/** @var int */
|
||||
private $_nextValue = 0;
|
||||
private $nextValue = 0;
|
||||
|
||||
/** @var int|null */
|
||||
private $_maxValue = null;
|
||||
private $maxValue = null;
|
||||
|
||||
/**
|
||||
* Initializes a new sequence generator.
|
||||
@@ -44,8 +44,8 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*/
|
||||
public function __construct($sequenceName, $allocationSize)
|
||||
{
|
||||
$this->_sequenceName = $sequenceName;
|
||||
$this->_allocationSize = $allocationSize;
|
||||
$this->sequenceName = $sequenceName;
|
||||
$this->allocationSize = $allocationSize;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,20 +53,20 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*/
|
||||
public function generateId(EntityManagerInterface $em, $entity)
|
||||
{
|
||||
if ($this->_maxValue === null || $this->_nextValue === $this->_maxValue) {
|
||||
if ($this->maxValue === null || $this->nextValue === $this->maxValue) {
|
||||
// Allocate new values
|
||||
$connection = $em->getConnection();
|
||||
$sql = $connection->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
|
||||
$sql = $connection->getDatabasePlatform()->getSequenceNextValSQL($this->sequenceName);
|
||||
|
||||
if ($connection instanceof PrimaryReadReplicaConnection) {
|
||||
$connection->ensureConnectedToPrimary();
|
||||
}
|
||||
|
||||
$this->_nextValue = (int) $connection->fetchOne($sql);
|
||||
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
|
||||
$this->nextValue = (int) $connection->fetchOne($sql);
|
||||
$this->maxValue = $this->nextValue + $this->allocationSize;
|
||||
}
|
||||
|
||||
return $this->_nextValue++;
|
||||
return $this->nextValue++;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +76,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*/
|
||||
public function getCurrentMaxValue()
|
||||
{
|
||||
return $this->_maxValue;
|
||||
return $this->maxValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,7 +86,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*/
|
||||
public function getNextValue()
|
||||
{
|
||||
return $this->_nextValue;
|
||||
return $this->nextValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,8 +103,8 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [
|
||||
'allocationSize' => $this->_allocationSize,
|
||||
'sequenceName' => $this->_sequenceName,
|
||||
'allocationSize' => $this->allocationSize,
|
||||
'sequenceName' => $this->sequenceName,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
/** @param array<string, mixed> $data */
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
$this->_sequenceName = $data['sequenceName'];
|
||||
$this->_allocationSize = $data['allocationSize'];
|
||||
$this->sequenceName = $data['sequenceName'];
|
||||
$this->allocationSize = $data['allocationSize'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,19 +14,19 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
class TableGenerator extends AbstractIdGenerator
|
||||
{
|
||||
/** @var string */
|
||||
private $_tableName;
|
||||
private $tableName;
|
||||
|
||||
/** @var string */
|
||||
private $_sequenceName;
|
||||
private $sequenceName;
|
||||
|
||||
/** @var int */
|
||||
private $_allocationSize;
|
||||
private $allocationSize;
|
||||
|
||||
/** @var int|null */
|
||||
private $_nextValue;
|
||||
private $nextValue;
|
||||
|
||||
/** @var int|null */
|
||||
private $_maxValue;
|
||||
private $maxValue;
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
@@ -35,9 +35,9 @@ class TableGenerator extends AbstractIdGenerator
|
||||
*/
|
||||
public function __construct($tableName, $sequenceName = 'default', $allocationSize = 10)
|
||||
{
|
||||
$this->_tableName = $tableName;
|
||||
$this->_sequenceName = $sequenceName;
|
||||
$this->_allocationSize = $allocationSize;
|
||||
$this->tableName = $tableName;
|
||||
$this->sequenceName = $sequenceName;
|
||||
$this->allocationSize = $allocationSize;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,23 +47,23 @@ class TableGenerator extends AbstractIdGenerator
|
||||
EntityManagerInterface $em,
|
||||
$entity
|
||||
) {
|
||||
if ($this->_maxValue === null || $this->_nextValue === $this->_maxValue) {
|
||||
if ($this->maxValue === null || $this->nextValue === $this->maxValue) {
|
||||
// Allocate new values
|
||||
$conn = $em->getConnection();
|
||||
|
||||
if ($conn->getTransactionNestingLevel() === 0) {
|
||||
// use select for update
|
||||
$sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName);
|
||||
$sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->tableName, $this->sequenceName);
|
||||
$currentLevel = $conn->fetchOne($sql);
|
||||
|
||||
if ($currentLevel !== null) {
|
||||
$this->_nextValue = $currentLevel;
|
||||
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
|
||||
$this->nextValue = $currentLevel;
|
||||
$this->maxValue = $this->nextValue + $this->allocationSize;
|
||||
|
||||
$updateSql = $conn->getDatabasePlatform()->getTableHiLoUpdateNextValSql(
|
||||
$this->_tableName,
|
||||
$this->_sequenceName,
|
||||
$this->_allocationSize
|
||||
$this->tableName,
|
||||
$this->sequenceName,
|
||||
$this->allocationSize
|
||||
);
|
||||
|
||||
if ($conn->executeStatement($updateSql, [1 => $currentLevel, 2 => $currentLevel + 1]) !== 1) {
|
||||
@@ -78,6 +78,6 @@ class TableGenerator extends AbstractIdGenerator
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_nextValue++;
|
||||
return $this->nextValue++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\CommitOrder;
|
||||
|
||||
/** @internal */
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
final class Edge
|
||||
{
|
||||
/**
|
||||
@@ -27,6 +32,13 @@ final class Edge
|
||||
|
||||
public function __construct(string $from, string $to, int $weight)
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10547',
|
||||
'The %s class is deprecated and will be removed in ORM 3.0',
|
||||
self::class
|
||||
);
|
||||
|
||||
$this->from = $from;
|
||||
$this->to = $to;
|
||||
$this->weight = $weight;
|
||||
|
||||
@@ -4,9 +4,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\CommitOrder;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
/** @internal */
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
final class Vertex
|
||||
{
|
||||
/**
|
||||
@@ -32,6 +36,13 @@ final class Vertex
|
||||
|
||||
public function __construct(string $hash, ClassMetadata $value)
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10547',
|
||||
'The %s class is deprecated and will be removed in ORM 3.0',
|
||||
self::class
|
||||
);
|
||||
|
||||
$this->hash = $hash;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\CommitOrder;
|
||||
|
||||
/** @internal */
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
final class VertexState
|
||||
{
|
||||
public const NOT_VISITED = 0;
|
||||
@@ -13,5 +18,11 @@ final class VertexState
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10547',
|
||||
'The %s class is deprecated and will be removed in ORM 3.0',
|
||||
self::class
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Internal\CommitOrder\Edge;
|
||||
use Doctrine\ORM\Internal\CommitOrder\Vertex;
|
||||
use Doctrine\ORM\Internal\CommitOrder\VertexState;
|
||||
@@ -17,6 +18,8 @@ use function array_reverse;
|
||||
* using a depth-first searching (DFS) to traverse the graph built in memory.
|
||||
* This algorithm have a linear running time based on nodes (V) and dependency
|
||||
* between the nodes (E), resulting in a computational complexity of O(V + E).
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
class CommitOrderCalculator
|
||||
{
|
||||
@@ -45,6 +48,16 @@ class CommitOrderCalculator
|
||||
*/
|
||||
private $sortedNodeList = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10547',
|
||||
'The %s class is deprecated and will be removed in ORM 3.0',
|
||||
self::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for node (vertex) existence in graph.
|
||||
*
|
||||
|
||||
@@ -19,39 +19,39 @@ use function reset;
|
||||
class ArrayHydrator extends AbstractHydrator
|
||||
{
|
||||
/** @var array<string,bool> */
|
||||
private $_rootAliases = [];
|
||||
private $rootAliases = [];
|
||||
|
||||
/** @var bool */
|
||||
private $_isSimpleQuery = false;
|
||||
private $isSimpleQuery = false;
|
||||
|
||||
/** @var mixed[] */
|
||||
private $_identifierMap = [];
|
||||
private $identifierMap = [];
|
||||
|
||||
/** @var mixed[] */
|
||||
private $_resultPointers = [];
|
||||
private $resultPointers = [];
|
||||
|
||||
/** @var array<string,string> */
|
||||
private $_idTemplate = [];
|
||||
private $idTemplate = [];
|
||||
|
||||
/** @var int */
|
||||
private $_resultCounter = 0;
|
||||
private $resultCounter = 0;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function prepare()
|
||||
{
|
||||
$this->_isSimpleQuery = count($this->resultSetMapping()->aliasMap) <= 1;
|
||||
$this->isSimpleQuery = count($this->resultSetMapping()->aliasMap) <= 1;
|
||||
|
||||
foreach ($this->resultSetMapping()->aliasMap as $dqlAlias => $className) {
|
||||
$this->_identifierMap[$dqlAlias] = [];
|
||||
$this->_resultPointers[$dqlAlias] = [];
|
||||
$this->_idTemplate[$dqlAlias] = '';
|
||||
$this->identifierMap[$dqlAlias] = [];
|
||||
$this->resultPointers[$dqlAlias] = [];
|
||||
$this->idTemplate[$dqlAlias] = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
@@ -65,12 +65,12 @@ class ArrayHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
// 1) Initialize
|
||||
$id = $this->_idTemplate; // initialize the id-memory
|
||||
$id = $this->idTemplate; // initialize the id-memory
|
||||
$nonemptyComponents = [];
|
||||
$rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
|
||||
|
||||
@@ -91,14 +91,14 @@ class ArrayHydrator extends AbstractHydrator
|
||||
|
||||
// Get a reference to the right element in the result tree.
|
||||
// This element will get the associated element attached.
|
||||
if ($this->resultSetMapping()->isMixed && isset($this->_rootAliases[$parent])) {
|
||||
$first = reset($this->_resultPointers);
|
||||
if ($this->resultSetMapping()->isMixed && isset($this->rootAliases[$parent])) {
|
||||
$first = reset($this->resultPointers);
|
||||
// TODO: Exception if $key === null ?
|
||||
$baseElement =& $this->_resultPointers[$parent][key($first)];
|
||||
} elseif (isset($this->_resultPointers[$parent])) {
|
||||
$baseElement =& $this->_resultPointers[$parent];
|
||||
$baseElement =& $this->resultPointers[$parent][key($first)];
|
||||
} elseif (isset($this->resultPointers[$parent])) {
|
||||
$baseElement =& $this->resultPointers[$parent];
|
||||
} else {
|
||||
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
|
||||
unset($this->resultPointers[$dqlAlias]); // Ticket #1228
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -116,8 +116,8 @@ class ArrayHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
if (isset($nonemptyComponents[$dqlAlias])) {
|
||||
$indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
|
||||
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
|
||||
$indexExists = isset($this->identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
|
||||
$index = $indexExists ? $this->identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
|
||||
$indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false;
|
||||
|
||||
if (! $indexExists || ! $indexIsValid) {
|
||||
@@ -131,7 +131,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
|
||||
end($baseElement[$relationAlias]);
|
||||
|
||||
$this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = key($baseElement[$relationAlias]);
|
||||
$this->identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = key($baseElement[$relationAlias]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -155,8 +155,8 @@ class ArrayHydrator extends AbstractHydrator
|
||||
} else {
|
||||
// It's a root result element
|
||||
|
||||
$this->_rootAliases[$dqlAlias] = true; // Mark as root
|
||||
$entityKey = $this->resultSetMapping()->entityMappings[$dqlAlias] ?: 0;
|
||||
$this->rootAliases[$dqlAlias] = true; // Mark as root
|
||||
$entityKey = $this->resultSetMapping()->entityMappings[$dqlAlias] ?: 0;
|
||||
|
||||
// if this row has a NULL value for the root result id then make it a null result.
|
||||
if (! isset($nonemptyComponents[$dqlAlias])) {
|
||||
@@ -164,14 +164,14 @@ class ArrayHydrator extends AbstractHydrator
|
||||
? [$entityKey => null]
|
||||
: null;
|
||||
|
||||
$resultKey = $this->_resultCounter;
|
||||
++$this->_resultCounter;
|
||||
$resultKey = $this->resultCounter;
|
||||
++$this->resultCounter;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for an existing element
|
||||
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||
if ($this->isSimpleQuery || ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||
$element = $this->resultSetMapping()->isMixed
|
||||
? [$entityKey => $data]
|
||||
: $data;
|
||||
@@ -180,15 +180,15 @@ class ArrayHydrator extends AbstractHydrator
|
||||
$resultKey = $row[$this->resultSetMapping()->indexByMap[$dqlAlias]];
|
||||
$result[$resultKey] = $element;
|
||||
} else {
|
||||
$resultKey = $this->_resultCounter;
|
||||
$resultKey = $this->resultCounter;
|
||||
$result[] = $element;
|
||||
|
||||
++$this->_resultCounter;
|
||||
++$this->resultCounter;
|
||||
}
|
||||
|
||||
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
|
||||
$this->identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
|
||||
} else {
|
||||
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
|
||||
$index = $this->identifierMap[$dqlAlias][$id[$dqlAlias]];
|
||||
$resultKey = $index;
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
if (! isset($resultKey)) {
|
||||
$this->_resultCounter++;
|
||||
$this->resultCounter++;
|
||||
}
|
||||
|
||||
// Append scalar values to mixed result sets
|
||||
@@ -206,7 +206,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
// this only ever happens when no object is fetched (scalar result only)
|
||||
$resultKey = isset($this->resultSetMapping()->indexByMap['scalars'])
|
||||
? $row[$this->resultSetMapping()->indexByMap['scalars']]
|
||||
: $this->_resultCounter - 1;
|
||||
: $this->resultCounter - 1;
|
||||
}
|
||||
|
||||
foreach ($rowData['scalars'] as $name => $value) {
|
||||
@@ -217,7 +217,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
// Append new object to mixed result sets
|
||||
if (isset($rowData['newObjects'])) {
|
||||
if (! isset($resultKey)) {
|
||||
$resultKey = $this->_resultCounter - 1;
|
||||
$resultKey = $this->resultCounter - 1;
|
||||
}
|
||||
|
||||
$scalarCount = (isset($rowData['scalars']) ? count($rowData['scalars']) : 0);
|
||||
@@ -253,19 +253,19 @@ class ArrayHydrator extends AbstractHydrator
|
||||
bool $oneToOne
|
||||
): void {
|
||||
if ($coll === null) {
|
||||
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
|
||||
unset($this->resultPointers[$dqlAlias]); // Ticket #1228
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($oneToOne) {
|
||||
$this->_resultPointers[$dqlAlias] =& $coll;
|
||||
$this->resultPointers[$dqlAlias] =& $coll;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($index !== false) {
|
||||
$this->_resultPointers[$dqlAlias] =& $coll[$index];
|
||||
$this->resultPointers[$dqlAlias] =& $coll[$index];
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -275,6 +275,6 @@ class ArrayHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
end($coll);
|
||||
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];
|
||||
$this->resultPointers[$dqlAlias] =& $coll[key($coll)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,21 +16,21 @@ use ReturnTypeWillChange;
|
||||
class IterableResult implements Iterator
|
||||
{
|
||||
/** @var AbstractHydrator */
|
||||
private $_hydrator;
|
||||
private $hydrator;
|
||||
|
||||
/** @var bool */
|
||||
private $_rewinded = false;
|
||||
private $rewinded = false;
|
||||
|
||||
/** @var int */
|
||||
private $_key = -1;
|
||||
private $key = -1;
|
||||
|
||||
/** @var mixed[]|null */
|
||||
private $_current = null;
|
||||
private $current = null;
|
||||
|
||||
/** @param AbstractHydrator $hydrator */
|
||||
public function __construct($hydrator)
|
||||
{
|
||||
$this->_hydrator = $hydrator;
|
||||
$this->hydrator = $hydrator;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,12 +41,12 @@ class IterableResult implements Iterator
|
||||
#[ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
{
|
||||
if ($this->_rewinded === true) {
|
||||
if ($this->rewinded === true) {
|
||||
throw new HydrationException('Can only iterate a Result once.');
|
||||
}
|
||||
|
||||
$this->_current = $this->next();
|
||||
$this->_rewinded = true;
|
||||
$this->current = $this->next();
|
||||
$this->rewinded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,30 +57,30 @@ class IterableResult implements Iterator
|
||||
#[ReturnTypeWillChange]
|
||||
public function next()
|
||||
{
|
||||
$this->_current = $this->_hydrator->hydrateRow();
|
||||
$this->_key++;
|
||||
$this->current = $this->hydrator->hydrateRow();
|
||||
$this->key++;
|
||||
|
||||
return $this->_current;
|
||||
return $this->current;
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
{
|
||||
return $this->_current;
|
||||
return $this->current;
|
||||
}
|
||||
|
||||
/** @return int */
|
||||
#[ReturnTypeWillChange]
|
||||
public function key()
|
||||
{
|
||||
return $this->_key;
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
#[ReturnTypeWillChange]
|
||||
public function valid()
|
||||
{
|
||||
return $this->_current !== false;
|
||||
return $this->current !== false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\Persistence\Proxy;
|
||||
|
||||
use function array_fill_keys;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function is_array;
|
||||
use function key;
|
||||
@@ -52,7 +52,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
private $existingCollections = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function prepare()
|
||||
{
|
||||
@@ -108,7 +108,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function cleanup()
|
||||
{
|
||||
@@ -139,7 +139,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
@@ -284,13 +284,17 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$class = $this->_metadataCache[$className];
|
||||
|
||||
if ($class->isIdentifierComposite) {
|
||||
$idHash = '';
|
||||
|
||||
foreach ($class->identifier as $fieldName) {
|
||||
$idHash .= ' ' . (isset($class->associationMappings[$fieldName])
|
||||
? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
|
||||
: $data[$fieldName]);
|
||||
}
|
||||
$idHash = UnitOfWork::getIdHashByIdentifier(
|
||||
array_map(
|
||||
/** @return mixed */
|
||||
static function (string $fieldName) use ($data, $class) {
|
||||
return isset($class->associationMappings[$fieldName])
|
||||
? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
|
||||
: $data[$fieldName];
|
||||
},
|
||||
$class->identifier
|
||||
)
|
||||
);
|
||||
|
||||
return $this->_uow->tryGetByIdHash(ltrim($idHash), $class->rootEntityName);
|
||||
} elseif (isset($class->associationMappings[$class->identifier[0]])) {
|
||||
@@ -308,7 +312,6 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* that belongs to a particular component/class. Afterwards, all these chunks
|
||||
* are processed, one after the other. For each chunk of class data only one of the
|
||||
* following code paths is executed:
|
||||
*
|
||||
* Path A: The data chunk belongs to a joined/associated object and the association
|
||||
* is collection-valued.
|
||||
* Path B: The data chunk belongs to a joined/associated object and the association
|
||||
@@ -435,7 +438,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
// PATH B: Single-valued association
|
||||
$reflFieldValue = $reflField->getValue($parentObject);
|
||||
|
||||
if (! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && ! $reflFieldValue->__isInitialized())) {
|
||||
if (! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || $this->_uow->isUninitializedObject($reflFieldValue)) {
|
||||
// we only need to take action if this value is null,
|
||||
// we refresh the entity or its an uninitialized proxy.
|
||||
if (isset($nonemptyComponents[$dqlAlias])) {
|
||||
@@ -453,9 +456,6 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($element, $parentObject);
|
||||
$this->_uow->setOriginalEntityProperty(spl_object_id($element), $inverseAssoc['fieldName'], $parentObject);
|
||||
}
|
||||
} elseif ($parentClass === $targetClass && $relation['mappedBy']) {
|
||||
// Special case: bi-directional self-referencing one-one on the same class
|
||||
$targetClass->reflFields[$relationField]->setValue($element, $parentObject);
|
||||
}
|
||||
} else {
|
||||
// For sure bidirectional, as there is no inverse side in unidirectional mappings
|
||||
|
||||
@@ -16,7 +16,7 @@ use function count;
|
||||
final class ScalarColumnHydrator extends AbstractHydrator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws MultipleSelectorsFoundException
|
||||
* @throws Exception
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Doctrine\ORM\Internal\Hydration;
|
||||
class ScalarHydrator extends AbstractHydrator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
@@ -26,7 +26,7 @@ class ScalarHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
private $class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function prepare()
|
||||
{
|
||||
@@ -44,7 +44,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function cleanup()
|
||||
{
|
||||
@@ -55,7 +55,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
@@ -71,7 +71,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ use function key;
|
||||
class SingleScalarHydrator extends AbstractHydrator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ final class HydrationCompleteHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should me called after any hydration cycle completed.
|
||||
* This method should be called after any hydration cycle completed.
|
||||
*
|
||||
* Method fires all deferred invocations of postLoad events
|
||||
*/
|
||||
|
||||
@@ -9,7 +9,9 @@ use Doctrine\DBAL\Platforms\DB2Platform;
|
||||
use Doctrine\DBAL\Platforms\OraclePlatform;
|
||||
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
|
||||
|
||||
use function get_class;
|
||||
use function method_exists;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function strtoupper;
|
||||
|
||||
@@ -26,7 +28,7 @@ trait SQLResultCasing
|
||||
return strtolower($column);
|
||||
}
|
||||
|
||||
if (method_exists(AbstractPlatform::class, 'getSQLResultCasing')) {
|
||||
if (strpos(get_class($platform), 'Doctrine\\DBAL\\Platforms\\') !== 0 && method_exists(AbstractPlatform::class, 'getSQLResultCasing')) {
|
||||
return $platform->getSQLResultCasing($column);
|
||||
}
|
||||
|
||||
|
||||
165
lib/Doctrine/ORM/Internal/TopologicalSort.php
Normal file
165
lib/Doctrine/ORM/Internal/TopologicalSort.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal;
|
||||
|
||||
use Doctrine\ORM\Internal\TopologicalSort\CycleDetectedException;
|
||||
|
||||
use function array_keys;
|
||||
use function array_reverse;
|
||||
use function array_unshift;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
* TopologicalSort implements topological sorting, which is an ordering
|
||||
* algorithm for directed graphs (DG) using a depth-first searching (DFS)
|
||||
* to traverse the graph built in memory.
|
||||
* This algorithm has a linear running time based on nodes (V) and edges
|
||||
* between the nodes (E), resulting in a computational complexity of O(V + E).
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class TopologicalSort
|
||||
{
|
||||
private const NOT_VISITED = 1;
|
||||
private const IN_PROGRESS = 2;
|
||||
private const VISITED = 3;
|
||||
|
||||
/**
|
||||
* Array of all nodes, indexed by object ids.
|
||||
*
|
||||
* @var array<int, object>
|
||||
*/
|
||||
private $nodes = [];
|
||||
|
||||
/**
|
||||
* DFS state for the different nodes, indexed by node object id and using one of
|
||||
* this class' constants as value.
|
||||
*
|
||||
* @var array<int, self::*>
|
||||
*/
|
||||
private $states = [];
|
||||
|
||||
/**
|
||||
* Edges between the nodes. The first-level key is the object id of the outgoing
|
||||
* node; the second array maps the destination node by object id as key. The final
|
||||
* boolean value indicates whether the edge is optional or not.
|
||||
*
|
||||
* @var array<int, array<int, bool>>
|
||||
*/
|
||||
private $edges = [];
|
||||
|
||||
/**
|
||||
* Builds up the result during the DFS.
|
||||
*
|
||||
* @var list<object>
|
||||
*/
|
||||
private $sortResult = [];
|
||||
|
||||
/** @param object $node */
|
||||
public function addNode($node): void
|
||||
{
|
||||
$id = spl_object_id($node);
|
||||
$this->nodes[$id] = $node;
|
||||
$this->states[$id] = self::NOT_VISITED;
|
||||
$this->edges[$id] = [];
|
||||
}
|
||||
|
||||
/** @param object $node */
|
||||
public function hasNode($node): bool
|
||||
{
|
||||
return isset($this->nodes[spl_object_id($node)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new edge between two nodes to the graph
|
||||
*
|
||||
* @param object $from
|
||||
* @param object $to
|
||||
* @param bool $optional This indicates whether the edge may be ignored during the topological sort if it is necessary to break cycles.
|
||||
*/
|
||||
public function addEdge($from, $to, bool $optional): void
|
||||
{
|
||||
$fromId = spl_object_id($from);
|
||||
$toId = spl_object_id($to);
|
||||
|
||||
if (isset($this->edges[$fromId][$toId]) && $this->edges[$fromId][$toId] === false) {
|
||||
return; // we already know about this dependency, and it is not optional
|
||||
}
|
||||
|
||||
$this->edges[$fromId][$toId] = $optional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a topological sort of all nodes. When we have an edge A->B between two nodes
|
||||
* A and B, then A will be listed before B in the result.
|
||||
*
|
||||
* @return list<object>
|
||||
*/
|
||||
public function sort(): array
|
||||
{
|
||||
/*
|
||||
* When possible, keep objects in the result in the same order in which they were added as nodes.
|
||||
* Since nodes are unshifted into $this->>sortResult (see the visit() method), that means we
|
||||
* need to work them in array_reverse order here.
|
||||
*/
|
||||
foreach (array_reverse(array_keys($this->nodes)) as $oid) {
|
||||
if ($this->states[$oid] === self::NOT_VISITED) {
|
||||
$this->visit($oid);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->sortResult;
|
||||
}
|
||||
|
||||
private function visit(int $oid): void
|
||||
{
|
||||
if ($this->states[$oid] === self::IN_PROGRESS) {
|
||||
// This node is already on the current DFS stack. We've found a cycle!
|
||||
throw new CycleDetectedException($this->nodes[$oid]);
|
||||
}
|
||||
|
||||
if ($this->states[$oid] === self::VISITED) {
|
||||
// We've reached a node that we've already seen, including all
|
||||
// other nodes that are reachable from here. We're done here, return.
|
||||
return;
|
||||
}
|
||||
|
||||
$this->states[$oid] = self::IN_PROGRESS;
|
||||
|
||||
// Continue the DFS downwards the edge list
|
||||
foreach ($this->edges[$oid] as $adjacentId => $optional) {
|
||||
try {
|
||||
$this->visit($adjacentId);
|
||||
} catch (CycleDetectedException $exception) {
|
||||
if ($exception->isCycleCollected()) {
|
||||
// There is a complete cycle downstream of the current node. We cannot
|
||||
// do anything about that anymore.
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
if ($optional) {
|
||||
// The current edge is part of a cycle, but it is optional and the closest
|
||||
// such edge while backtracking. Break the cycle here by skipping the edge
|
||||
// and continuing with the next one.
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have found a cycle and cannot break it at $edge. Best we can do
|
||||
// is to retreat from the current vertex, hoping that somewhere up the
|
||||
// stack this can be salvaged.
|
||||
$this->states[$oid] = self::NOT_VISITED;
|
||||
$exception->addToCycle($this->nodes[$oid]);
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
// We have traversed all edges and visited all other nodes reachable from here.
|
||||
// So we're done with this vertex as well.
|
||||
|
||||
$this->states[$oid] = self::VISITED;
|
||||
array_unshift($this->sortResult, $this->nodes[$oid]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\TopologicalSort;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
use function array_unshift;
|
||||
|
||||
class CycleDetectedException extends RuntimeException
|
||||
{
|
||||
/** @var list<object> */
|
||||
private $cycle;
|
||||
|
||||
/** @var object */
|
||||
private $startNode;
|
||||
|
||||
/**
|
||||
* Do we have the complete cycle collected?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $cycleCollected = false;
|
||||
|
||||
/** @param object $startNode */
|
||||
public function __construct($startNode)
|
||||
{
|
||||
parent::__construct('A cycle has been detected, so a topological sort is not possible. The getCycle() method provides the list of nodes that form the cycle.');
|
||||
|
||||
$this->startNode = $startNode;
|
||||
$this->cycle = [$startNode];
|
||||
}
|
||||
|
||||
/** @return list<object> */
|
||||
public function getCycle(): array
|
||||
{
|
||||
return $this->cycle;
|
||||
}
|
||||
|
||||
/** @param object $node */
|
||||
public function addToCycle($node): void
|
||||
{
|
||||
array_unshift($this->cycle, $node);
|
||||
|
||||
if ($node === $this->startNode) {
|
||||
$this->cycleCollected = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function isCycleCollected(): bool
|
||||
{
|
||||
return $this->cycleCollected;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
use SQLResultCasing;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -24,7 +24,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getTableName(ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -32,7 +32,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -40,7 +40,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -48,7 +48,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -56,7 +56,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -64,7 +64,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -72,7 +72,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ?ClassMetadata $class = null)
|
||||
{
|
||||
|
||||
@@ -220,10 +220,11 @@ class ClassMetadataBuilder
|
||||
* @param string $type
|
||||
* @param int $length
|
||||
* @psalm-param class-string<BackedEnum>|null $enumType
|
||||
* @psalm-param array<string, mixed> $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDiscriminatorColumn($name, $type = 'string', $length = 255, ?string $columnDefinition = null, ?string $enumType = null)
|
||||
public function setDiscriminatorColumn($name, $type = 'string', $length = 255, ?string $columnDefinition = null, ?string $enumType = null, array $options = [])
|
||||
{
|
||||
$this->cm->setDiscriminatorColumn(
|
||||
[
|
||||
@@ -232,6 +233,7 @@ class ClassMetadataBuilder
|
||||
'length' => $length,
|
||||
'columnDefinition' => $columnDefinition,
|
||||
'enumType' => $enumType,
|
||||
'options' => $options,
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ final class ChainTypedFieldMapper implements TypedFieldMapper
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validateAndComplete(array $mapping, ReflectionProperty $field): array
|
||||
{
|
||||
|
||||
@@ -4,12 +4,102 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use BackedEnum;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @todo remove or rename ClassMetadataInfo to ClassMetadata
|
||||
* @template-covariant T of object
|
||||
* @template-extends ClassMetadataInfo<T>
|
||||
* @psalm-type FieldMapping = array{
|
||||
* type: string,
|
||||
* fieldName: string,
|
||||
* columnName: string,
|
||||
* length?: int,
|
||||
* id?: bool,
|
||||
* nullable?: bool,
|
||||
* notInsertable?: bool,
|
||||
* notUpdatable?: bool,
|
||||
* generated?: int,
|
||||
* enumType?: class-string<BackedEnum>,
|
||||
* columnDefinition?: string,
|
||||
* precision?: int,
|
||||
* scale?: int,
|
||||
* unique?: bool,
|
||||
* inherited?: class-string,
|
||||
* originalClass?: class-string,
|
||||
* originalField?: string,
|
||||
* quoted?: bool,
|
||||
* requireSQLConversion?: bool,
|
||||
* declared?: class-string,
|
||||
* declaredField?: string,
|
||||
* options?: array<string, mixed>,
|
||||
* version?: string,
|
||||
* default?: string|int,
|
||||
* }
|
||||
* @psalm-type JoinColumnData = array{
|
||||
* name: string,
|
||||
* referencedColumnName: string,
|
||||
* unique?: bool,
|
||||
* quoted?: bool,
|
||||
* fieldName?: string,
|
||||
* onDelete?: string,
|
||||
* columnDefinition?: string,
|
||||
* nullable?: bool,
|
||||
* }
|
||||
* @psalm-type AssociationMapping = array{
|
||||
* cache?: array,
|
||||
* cascade: array<string>,
|
||||
* declared?: class-string,
|
||||
* fetch: mixed,
|
||||
* fieldName: string,
|
||||
* id?: bool,
|
||||
* inherited?: class-string,
|
||||
* indexBy?: string,
|
||||
* inversedBy: string|null,
|
||||
* isCascadeRemove: bool,
|
||||
* isCascadePersist: bool,
|
||||
* isCascadeRefresh: bool,
|
||||
* isCascadeMerge: bool,
|
||||
* isCascadeDetach: bool,
|
||||
* isOnDeleteCascade?: bool,
|
||||
* isOwningSide: bool,
|
||||
* joinColumns?: array<JoinColumnData>,
|
||||
* joinColumnFieldNames?: array<string, string>,
|
||||
* joinTable?: array,
|
||||
* joinTableColumns?: list<mixed>,
|
||||
* mappedBy: string|null,
|
||||
* orderBy?: array,
|
||||
* originalClass?: class-string,
|
||||
* originalField?: string,
|
||||
* orphanRemoval?: bool,
|
||||
* relationToSourceKeyColumns?: array,
|
||||
* relationToTargetKeyColumns?: array,
|
||||
* sourceEntity: class-string,
|
||||
* sourceToTargetKeyColumns?: array<string, string>,
|
||||
* targetEntity: class-string,
|
||||
* targetToSourceKeyColumns?: array<string, string>,
|
||||
* type: int,
|
||||
* unique?: bool,
|
||||
* }
|
||||
* @psalm-type DiscriminatorColumnMapping = array{
|
||||
* name: string,
|
||||
* fieldName: string,
|
||||
* type: string,
|
||||
* length?: int,
|
||||
* columnDefinition?: string|null,
|
||||
* enumType?: class-string<BackedEnum>|null,
|
||||
* options?: array<string, mixed>,
|
||||
* }
|
||||
* @psalm-type EmbeddedClassMapping = array{
|
||||
* class: class-string,
|
||||
* columnPrefix: string|null,
|
||||
* declaredField: string|null,
|
||||
* originalField: string|null,
|
||||
* inherited?: class-string,
|
||||
* declared?: class-string,
|
||||
* }
|
||||
*/
|
||||
class ClassMetadata extends ClassMetadataInfo
|
||||
{
|
||||
|
||||
@@ -7,6 +7,9 @@ namespace Doctrine\ORM\Mapping;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\DBAL\Platforms;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Platforms\MySQLPlatform;
|
||||
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
||||
use Doctrine\DBAL\Platforms\SQLServerPlatform;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
|
||||
@@ -47,6 +50,9 @@ use function substr;
|
||||
* to a relational database.
|
||||
*
|
||||
* @extends AbstractClassMetadataFactory<ClassMetadata>
|
||||
* @psalm-import-type AssociationMapping from ClassMetadata
|
||||
* @psalm-import-type EmbeddedClassMapping from ClassMetadata
|
||||
* @psalm-import-type FieldMapping from ClassMetadata
|
||||
*/
|
||||
class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
{
|
||||
@@ -107,7 +113,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
if ($parent) {
|
||||
$class->setInheritanceType($parent->inheritanceType);
|
||||
$class->setDiscriminatorColumn($parent->discriminatorColumn);
|
||||
$class->setIdGeneratorType($parent->generatorType);
|
||||
$this->inheritIdGeneratorMapping($class, $parent);
|
||||
$this->addInheritedFields($class, $parent);
|
||||
$this->addInheritedRelations($class, $parent);
|
||||
$this->addInheritedEmbeddedClasses($class, $parent);
|
||||
@@ -135,25 +141,27 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
throw MappingException::reflectionFailure($class->getName(), $e);
|
||||
}
|
||||
|
||||
// If this class has a parent the id generator strategy is inherited.
|
||||
// However this is only true if the hierarchy of parents contains the root entity,
|
||||
// if it consists of mapped superclasses these don't necessarily include the id field.
|
||||
if ($parent && $rootEntityFound) {
|
||||
$this->inheritIdGeneratorMapping($class, $parent);
|
||||
} else {
|
||||
// Complete id generator mapping when the generator was declared/added in this class
|
||||
if ($class->identifier && (! $parent || ! $parent->identifier)) {
|
||||
$this->completeIdGeneratorMapping($class);
|
||||
}
|
||||
|
||||
if (! $class->isMappedSuperclass) {
|
||||
if ($rootEntityFound && $class->isInheritanceTypeNone()) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10431',
|
||||
"Entity class '%s' is a subclass of the root entity class '%s', but no inheritance mapping type was declared. This is a misconfiguration and will be an error in Doctrine ORM 3.0.",
|
||||
$class->name,
|
||||
end($nonSuperclassParents)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($class->embeddedClasses as $property => $embeddableClass) {
|
||||
if (isset($embeddableClass['inherited'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! (isset($embeddableClass['class']) && $embeddableClass['class'])) {
|
||||
throw MappingException::missingEmbeddedClass($property);
|
||||
}
|
||||
|
||||
if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) {
|
||||
throw MappingException::infiniteEmbeddableNesting($class->name, $property);
|
||||
}
|
||||
@@ -411,20 +419,30 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
return strtolower(end($parts));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the `inherited` and `declared` values into mapping information for fields, associations
|
||||
* and embedded classes.
|
||||
*
|
||||
* @param AssociationMapping|EmbeddedClassMapping|FieldMapping $mapping
|
||||
*/
|
||||
private function addMappingInheritanceInformation(array &$mapping, ClassMetadata $parentClass): void
|
||||
{
|
||||
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$mapping['inherited'] = $parentClass->name;
|
||||
}
|
||||
|
||||
if (! isset($mapping['declared'])) {
|
||||
$mapping['declared'] = $parentClass->name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds inherited fields to the subclass mapping.
|
||||
*/
|
||||
private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass): void
|
||||
{
|
||||
foreach ($parentClass->fieldMappings as $mapping) {
|
||||
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$mapping['inherited'] = $parentClass->name;
|
||||
}
|
||||
|
||||
if (! isset($mapping['declared'])) {
|
||||
$mapping['declared'] = $parentClass->name;
|
||||
}
|
||||
|
||||
$this->addMappingInheritanceInformation($mapping, $parentClass);
|
||||
$subClass->addInheritedFieldMapping($mapping);
|
||||
}
|
||||
|
||||
@@ -441,14 +459,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass): void
|
||||
{
|
||||
foreach ($parentClass->associationMappings as $field => $mapping) {
|
||||
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$mapping['inherited'] = $parentClass->name;
|
||||
}
|
||||
|
||||
if (! isset($mapping['declared'])) {
|
||||
$mapping['declared'] = $parentClass->name;
|
||||
}
|
||||
|
||||
$this->addMappingInheritanceInformation($mapping, $parentClass);
|
||||
// When the class inheriting the relation ($subClass) is the first entity class since the
|
||||
// relation has been defined in a mapped superclass (or in a chain
|
||||
// of mapped superclasses) above, then declare this current entity class as the source of
|
||||
@@ -456,10 +467,6 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
// According to the definitions given in https://github.com/doctrine/orm/pull/10396/,
|
||||
// this is the case <=> ! isset($mapping['inherited']).
|
||||
if (! isset($mapping['inherited'])) {
|
||||
if ($mapping['type'] & ClassMetadata::TO_MANY && ! $mapping['isOwningSide']) {
|
||||
throw MappingException::illegalToManyAssociationOnMappedSuperclass($parentClass->name, $field);
|
||||
}
|
||||
|
||||
$mapping['sourceEntity'] = $subClass->name;
|
||||
}
|
||||
|
||||
@@ -470,14 +477,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
private function addInheritedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass): void
|
||||
{
|
||||
foreach ($parentClass->embeddedClasses as $field => $embeddedClass) {
|
||||
if (! isset($embeddedClass['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$embeddedClass['inherited'] = $parentClass->name;
|
||||
}
|
||||
|
||||
if (! isset($embeddedClass['declared'])) {
|
||||
$embeddedClass['declared'] = $parentClass->name;
|
||||
}
|
||||
|
||||
$this->addMappingInheritanceInformation($embeddedClass, $parentClass);
|
||||
$subClass->embeddedClasses[$field] = $embeddedClass;
|
||||
}
|
||||
}
|
||||
@@ -620,9 +620,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
case ClassMetadata::GENERATOR_TYPE_IDENTITY:
|
||||
$sequenceName = null;
|
||||
$fieldName = $class->identifier ? $class->getSingleIdentifierFieldName() : null;
|
||||
$platform = $this->getTargetPlatform();
|
||||
|
||||
// Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
|
||||
if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) {
|
||||
/** @psalm-suppress UndefinedClass, InvalidClass */
|
||||
if (! $platform instanceof MySQLPlatform && ! $platform instanceof SqlitePlatform && ! $platform instanceof SQLServerPlatform && $platform->usesSequenceEmulatedIdentityColumns()) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/8850',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user