mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 06:52:09 +01:00
Compare commits
355 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ab6b74f14 | ||
|
|
71550106d4 | ||
|
|
36011f0d0f | ||
|
|
c97d775370 | ||
|
|
e9f0345a97 | ||
|
|
05c8c5f114 | ||
|
|
1dbdb0e895 | ||
|
|
0feb09d0d6 | ||
|
|
fe5f8bbaa1 | ||
|
|
ecf3cec376 | ||
|
|
0a714db4d9 | ||
|
|
471fda8d0b | ||
|
|
dfe32c2f74 | ||
|
|
c51ba3ce6b | ||
|
|
fe025e8d23 | ||
|
|
7111cc09f3 | ||
|
|
777504b9c4 | ||
|
|
9d9985076a | ||
|
|
ae2957cf7e | ||
|
|
e172b3bf9c | ||
|
|
c9c6e8da2e | ||
|
|
1f1891d3e2 | ||
|
|
c9fc4d90e5 | ||
|
|
17d28b5c4c | ||
|
|
a2d510c6f4 | ||
|
|
0e3cff0c6a | ||
|
|
5c50ed925a | ||
|
|
5a1e560f87 | ||
|
|
78e8887759 | ||
|
|
5eb298b99b | ||
|
|
5eb0255f47 | ||
|
|
28575f58af | ||
|
|
457d2d2841 | ||
|
|
2a4ebca90e | ||
|
|
5d01c66c84 | ||
|
|
a2516b67dc | ||
|
|
3d4e9b3ecf | ||
|
|
d1ee40e7d5 | ||
|
|
65d2720764 | ||
|
|
3e18a58de6 | ||
|
|
a9f9202c00 | ||
|
|
d8cb71fe4a | ||
|
|
d659591b6c | ||
|
|
e2430ac9a7 | ||
|
|
0b373f6c27 | ||
|
|
36b9064dbe | ||
|
|
cc29ae0d36 | ||
|
|
bd4a053d29 | ||
|
|
52fbfb3785 | ||
|
|
c259371e5f | ||
|
|
dcdd58b642 | ||
|
|
7b9c53854f | ||
|
|
cdc5fe11dd | ||
|
|
69ece00564 | ||
|
|
4baa7bd252 | ||
|
|
c55f10e501 | ||
|
|
f3fb79658e | ||
|
|
10a32cb824 | ||
|
|
c679d1b007 | ||
|
|
1e15b22dcb | ||
|
|
d88371331d | ||
|
|
b260ec8a00 | ||
|
|
44057b4683 | ||
|
|
013df03795 | ||
|
|
2d2a34407c | ||
|
|
1072ea6db4 | ||
|
|
baf2c60cc4 | ||
|
|
8e620cad40 | ||
|
|
daf0f82884 | ||
|
|
3303cd3b5d | ||
|
|
afcf91e839 | ||
|
|
c61a9b3b6d | ||
|
|
bd0509a064 | ||
|
|
708bd84fe2 | ||
|
|
3aed6912a3 | ||
|
|
36bef3f959 | ||
|
|
980ccc58dc | ||
|
|
62ca4624a9 | ||
|
|
1aed318b7b | ||
|
|
8ce7b310c5 | ||
|
|
158605bf24 | ||
|
|
2c2ef65817 | ||
|
|
f8fdeaf41e | ||
|
|
1c33a86983 | ||
|
|
310fe1cccb | ||
|
|
a67f677747 | ||
|
|
c9557c588b | ||
|
|
19912de927 | ||
|
|
737cca5b78 | ||
|
|
aff82af7de | ||
|
|
9e999ea1ff | ||
|
|
6755bb0c7b | ||
|
|
aa141bf001 | ||
|
|
cf39e00553 | ||
|
|
27b47841be | ||
|
|
c2a49327a7 | ||
|
|
9bd7242376 | ||
|
|
fff085b63f | ||
|
|
5ad5b11ae1 | ||
|
|
c12fd2cb94 | ||
|
|
44d5d4a779 | ||
|
|
5a599233c9 | ||
|
|
596da353c2 | ||
|
|
68c87740aa | ||
|
|
55dc02c39f | ||
|
|
b1f8253105 | ||
|
|
e3cabade99 | ||
|
|
9402f9e0f7 | ||
|
|
4feaa470af | ||
|
|
4a9101f383 | ||
|
|
f91da5b950 | ||
|
|
66f654d4e2 | ||
|
|
7b9c0d91f6 | ||
|
|
53b51ae40e | ||
|
|
95b0f5c328 | ||
|
|
46c94e3729 | ||
|
|
4e01567816 | ||
|
|
f7f3104451 | ||
|
|
a5c80a4c75 | ||
|
|
417444d4b5 | ||
|
|
6fd26a3933 | ||
|
|
8ef9253999 | ||
|
|
360b80afab | ||
|
|
0ed0be089c | ||
|
|
8fb1043e96 | ||
|
|
fd041fbe80 | ||
|
|
5d73458f0b | ||
|
|
6c70d11f4e | ||
|
|
eadf96c879 | ||
|
|
0d770c89d6 | ||
|
|
0a635c1ece | ||
|
|
69a4199434 | ||
|
|
4bda5147f3 | ||
|
|
cbda7e2322 | ||
|
|
38c6569645 | ||
|
|
7c0eebe90a | ||
|
|
8784f2bce9 | ||
|
|
fbcac42ebd | ||
|
|
619302dc9a | ||
|
|
50d7a0f95e | ||
|
|
d7f13a82ef | ||
|
|
9e1038075e | ||
|
|
dd3604f523 | ||
|
|
65e9f607e5 | ||
|
|
a42134ccee | ||
|
|
71e038c81d | ||
|
|
2ff998da0e | ||
|
|
82e2c981da | ||
|
|
8422a41423 | ||
|
|
58ad1d9678 | ||
|
|
346c49832c | ||
|
|
f140651ff0 | ||
|
|
bb5b2a3300 | ||
|
|
5013d5dbef | ||
|
|
ba11851ac4 | ||
|
|
4fbce94999 | ||
|
|
486e406236 | ||
|
|
7d1b24f3b1 | ||
|
|
43ce0bef78 | ||
|
|
da51234d5a | ||
|
|
d9aa6ef6dc | ||
|
|
ff3ccff36a | ||
|
|
4b03ec7789 | ||
|
|
14866461c5 | ||
|
|
f41dc4a503 | ||
|
|
81c0d599c9 | ||
|
|
9e2bfa8169 | ||
|
|
44fa8bbde8 | ||
|
|
3ca9529c32 | ||
|
|
439b4dacf4 | ||
|
|
05f54860f7 | ||
|
|
021a9cce3d | ||
|
|
0f11a97c8e | ||
|
|
c9253ef64b | ||
|
|
af54a1696c | ||
|
|
4d821cb139 | ||
|
|
85fc95060f | ||
|
|
039b03255a | ||
|
|
e7efdede15 | ||
|
|
74155c8672 | ||
|
|
9c0e62ad44 | ||
|
|
94702d14b9 | ||
|
|
5aad44cff6 | ||
|
|
182469b346 | ||
|
|
0893d8511e | ||
|
|
e47398ecc5 | ||
|
|
9e884ccf1f | ||
|
|
fac0899ef7 | ||
|
|
d5c400e8d1 | ||
|
|
6648d68ddf | ||
|
|
982d6060a3 | ||
|
|
013f850c76 | ||
|
|
ef4508e52f | ||
|
|
6dae89ce0d | ||
|
|
f53350934f | ||
|
|
efaba02ef5 | ||
|
|
4ff909044e | ||
|
|
32682aa14d | ||
|
|
e9f3ca2a45 | ||
|
|
737aee7d98 | ||
|
|
bd20df1043 | ||
|
|
69958152e6 | ||
|
|
cf8f5f9f93 | ||
|
|
60c245413d | ||
|
|
7c9b74221f | ||
|
|
2ec2030ab2 | ||
|
|
c7e5605d11 | ||
|
|
c19afa1529 | ||
|
|
516b593193 | ||
|
|
e2b971d7c5 | ||
|
|
19d9244a88 | ||
|
|
10a5a3ff73 | ||
|
|
f5fb400d0f | ||
|
|
a321331c89 | ||
|
|
522863116a | ||
|
|
5bfb744967 | ||
|
|
8ed6c2234a | ||
|
|
ff612b9678 | ||
|
|
ee0d7197dd | ||
|
|
39d2136f46 | ||
|
|
c223b8f635 | ||
|
|
bea454eefc | ||
|
|
14f2572e4e | ||
|
|
c2c500077b | ||
|
|
6281c2b79f | ||
|
|
bac1c17eab | ||
|
|
b6137c8911 | ||
|
|
da7854f586 | ||
|
|
5f4ecfd1d8 | ||
|
|
51be1b1d52 | ||
|
|
5f39343bfd | ||
|
|
7ef1f0a379 | ||
|
|
488a5dd3bf | ||
|
|
30795559dc | ||
|
|
f71725575c | ||
|
|
4a3c7f05bf | ||
|
|
896c65504d | ||
|
|
16a8f10fd2 | ||
|
|
498de4c564 | ||
|
|
d80a831157 | ||
|
|
52660297ab | ||
|
|
b44774285b | ||
|
|
58287bb731 | ||
|
|
bc37f75b41 | ||
|
|
8a25b264f7 | ||
|
|
0e48b19cd3 | ||
|
|
d2978303f0 | ||
|
|
109042e5af | ||
|
|
08328adc6c | ||
|
|
191a5366b1 | ||
|
|
65806884b0 | ||
|
|
ad80e8281a | ||
|
|
44dddb2eee | ||
|
|
0c0c61c51b | ||
|
|
cc28fed9f5 | ||
|
|
2245149588 | ||
|
|
b13564c6c0 | ||
|
|
91709c1275 | ||
|
|
434b7cee2a | ||
|
|
7f0a181e39 | ||
|
|
d18126aac5 | ||
|
|
b7fd8241cf | ||
|
|
2432939e4f | ||
|
|
93ce84fa6e | ||
|
|
1bf4603422 | ||
|
|
e6961bd968 | ||
|
|
25d5bc5b46 | ||
|
|
5724e6279e | ||
|
|
cfc0655a1c | ||
|
|
6cde337777 | ||
|
|
c6b2d89748 | ||
|
|
e1dc94d1c2 | ||
|
|
74ef28295a | ||
|
|
831a1eb7d2 | ||
|
|
3a82b153f3 | ||
|
|
168ac31084 | ||
|
|
6f93cebe6e | ||
|
|
8c582a49d3 | ||
|
|
5f1fe1587c | ||
|
|
fe4a2e83cf | ||
|
|
205b2f5f20 | ||
|
|
3f550c19e3 | ||
|
|
8ac6a13ca0 | ||
|
|
2707b09a07 | ||
|
|
121158f92c | ||
|
|
56cd688c4a | ||
|
|
96546caceb | ||
|
|
57247ed6ca | ||
|
|
12817076c3 | ||
|
|
129553da90 | ||
|
|
4c2f104d42 | ||
|
|
ef64cf7c33 | ||
|
|
0983d3a4af | ||
|
|
51ad860a25 | ||
|
|
9bd51aaeb6 | ||
|
|
1fe1a6a048 | ||
|
|
c37b115450 | ||
|
|
19129e9f8a | ||
|
|
efe62e3f0b | ||
|
|
7d01f19667 | ||
|
|
722cea6536 | ||
|
|
c1bb2ccf4b | ||
|
|
e3d7c6076c | ||
|
|
ce7d93f14d | ||
|
|
a139a1b63c | ||
|
|
1153b9468c | ||
|
|
40f299f1eb | ||
|
|
d0e9177121 | ||
|
|
428032ca7c | ||
|
|
68af854f46 | ||
|
|
77467cd824 | ||
|
|
f666aa641e | ||
|
|
ca3319c2f6 | ||
|
|
c06f6b9376 | ||
|
|
802f20b8e7 | ||
|
|
96d13ac62a | ||
|
|
ed53defaa1 | ||
|
|
2ea6a1a5fb | ||
|
|
41cb5fbbbf | ||
|
|
83851a9716 | ||
|
|
066ec1ac81 | ||
|
|
68744489f0 | ||
|
|
cc2ad1993c | ||
|
|
e4d46c4276 | ||
|
|
858a1adc3b | ||
|
|
3b499132d9 | ||
|
|
39153fd88a | ||
|
|
bdc9679e37 | ||
|
|
87a8ee21c9 | ||
|
|
59c8bc09ab | ||
|
|
3a7d7c9f57 | ||
|
|
06eca40134 | ||
|
|
23b35e9554 | ||
|
|
e063926cbd | ||
|
|
4a01a76a17 | ||
|
|
93c2dd9d4b | ||
|
|
75bc22980e | ||
|
|
9696c3434d | ||
|
|
9d4f54b9a4 | ||
|
|
bf3e082c00 | ||
|
|
eb49f66926 | ||
|
|
73e30df52b | ||
|
|
8b6a58fa0e | ||
|
|
b725908c83 | ||
|
|
be307edba8 | ||
|
|
083f642cfa | ||
|
|
716da7e538 | ||
|
|
bcdc5bdaf4 | ||
|
|
80278c545e | ||
|
|
90962f060a | ||
|
|
758f0d7605 | ||
|
|
eb8510ff5c | ||
|
|
d5fdd676f4 | ||
|
|
a3e3a3bbf3 | ||
|
|
0a49274f9b |
@@ -11,17 +11,29 @@
|
||||
"slug": "latest",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "3.4",
|
||||
"branchName": "3.4.x",
|
||||
"slug": "3.4",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "3.3",
|
||||
"branchName": "3.3.x",
|
||||
"slug": "3.3",
|
||||
"current": true
|
||||
},
|
||||
{
|
||||
"name": "3.2",
|
||||
"branchName": "3.2.x",
|
||||
"slug": "3.2",
|
||||
"upcoming": true
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "3.1",
|
||||
"branchName": "3.1.x",
|
||||
"slug": "3.1",
|
||||
"current": true
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "3.0",
|
||||
@@ -29,17 +41,23 @@
|
||||
"slug": "3.0",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.21",
|
||||
"branchName": "2.21.x",
|
||||
"slug": "2.21",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.20",
|
||||
"branchName": "2.20.x",
|
||||
"slug": "2.20",
|
||||
"upcoming": true
|
||||
"maintained": true
|
||||
},
|
||||
{
|
||||
"name": "2.19",
|
||||
"branchName": "2.19.x",
|
||||
"slug": "2.19",
|
||||
"maintained": true
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.18",
|
||||
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -19,5 +19,3 @@ phpstan-baseline.neon export-ignore
|
||||
phpstan-dbal2.neon export-ignore
|
||||
phpstan-params.neon export-ignore
|
||||
phpstan-persistence2.neon export-ignore
|
||||
psalm.xml export-ignore
|
||||
psalm-baseline.xml export-ignore
|
||||
|
||||
37
.github/ISSUE_TEMPLATE/BC_Break.md
vendored
37
.github/ISSUE_TEMPLATE/BC_Break.md
vendored
@@ -1,37 +0,0 @@
|
||||
---
|
||||
name: 💥 BC Break
|
||||
about: Have you encountered an issue during upgrade? 💣
|
||||
---
|
||||
|
||||
<!--
|
||||
Before reporting a BC break, please consult the upgrading document to make sure it's not an expected change: https://github.com/doctrine/orm/blob/2.9.x/UPGRADE.md
|
||||
-->
|
||||
|
||||
### BC Break Report
|
||||
|
||||
<!-- Fill in the relevant information below to help triage your issue. -->
|
||||
|
||||
| Q | A
|
||||
|------------ | ------
|
||||
| BC Break | yes
|
||||
| Version | x.y.z
|
||||
|
||||
#### Summary
|
||||
|
||||
<!-- Provide a summary describing the problem you are experiencing. -->
|
||||
|
||||
#### Previous behavior
|
||||
|
||||
<!-- What was the previous (working) behavior? -->
|
||||
|
||||
#### Current behavior
|
||||
|
||||
<!-- What is the current (broken) behavior? -->
|
||||
|
||||
#### How to reproduce
|
||||
|
||||
<!--
|
||||
Provide steps to reproduce the BC break.
|
||||
If possible, also add a code snippet with relevant configuration, entity mappings, DQL etc.
|
||||
Adding a failing Unit or Functional Test would help us a lot - you can submit it in a Pull Request separately, referencing this bug report.
|
||||
-->
|
||||
34
.github/ISSUE_TEMPLATE/Bug.md
vendored
34
.github/ISSUE_TEMPLATE/Bug.md
vendored
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: 🐞 Bug Report
|
||||
about: Something is broken? 🔨
|
||||
---
|
||||
|
||||
### Bug Report
|
||||
|
||||
<!-- Fill in the relevant information below to help triage your issue. -->
|
||||
|
||||
| Q | A
|
||||
|------------ | ------
|
||||
| BC Break | yes/no
|
||||
| Version | x.y.z
|
||||
|
||||
#### Summary
|
||||
|
||||
<!-- Provide a summary describing the problem you are experiencing. -->
|
||||
|
||||
#### Current behavior
|
||||
|
||||
<!-- What is the current (buggy) behavior? -->
|
||||
|
||||
#### How to reproduce
|
||||
|
||||
<!--
|
||||
Provide steps to reproduce the bug.
|
||||
If possible, also add a code snippet with relevant configuration, entity mappings, DQL etc.
|
||||
Adding a failing Unit or Functional Test would help us a lot - you can submit one in a Pull Request separately, referencing this bug report.
|
||||
-->
|
||||
|
||||
#### Expected behavior
|
||||
|
||||
<!-- What was the expected (correct) behavior? -->
|
||||
|
||||
18
.github/ISSUE_TEMPLATE/Feature_Request.md
vendored
18
.github/ISSUE_TEMPLATE/Feature_Request.md
vendored
@@ -1,18 +0,0 @@
|
||||
---
|
||||
name: 🎉 Feature Request
|
||||
about: You have a neat idea that should be implemented? 🎩
|
||||
---
|
||||
|
||||
### Feature Request
|
||||
|
||||
<!-- Fill in the relevant information below to help triage your issue. -->
|
||||
|
||||
| Q | A
|
||||
|------------ | ------
|
||||
| New Feature | yes
|
||||
| RFC | yes/no
|
||||
| BC Break | yes/no
|
||||
|
||||
#### Summary
|
||||
|
||||
<!-- Provide a summary of the feature you would like to see implemented. -->
|
||||
6
.github/ISSUE_TEMPLATE/Support_Question.md
vendored
6
.github/ISSUE_TEMPLATE/Support_Question.md
vendored
@@ -1,6 +0,0 @@
|
||||
---
|
||||
name: ❓ Support Question
|
||||
about: Have a problem that you can't figure out? 🤔
|
||||
---
|
||||
|
||||
Please use https://github.com/doctrine/orm/discussions instead.
|
||||
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@@ -6,4 +6,4 @@ updates:
|
||||
interval: "weekly"
|
||||
labels:
|
||||
- "CI"
|
||||
target-branch: "2.19.x"
|
||||
target-branch: "2.20.x"
|
||||
|
||||
2
.github/workflows/coding-standards.yml
vendored
2
.github/workflows/coding-standards.yml
vendored
@@ -24,4 +24,4 @@ on:
|
||||
|
||||
jobs:
|
||||
coding-standards:
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@5.0.1"
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.3.0"
|
||||
|
||||
20
.github/workflows/continuous-integration.yml
vendored
20
.github/workflows/continuous-integration.yml
vendored
@@ -9,7 +9,6 @@ on:
|
||||
- ci/**
|
||||
- composer.*
|
||||
- src/**
|
||||
- phpunit.xml.dist
|
||||
- tests/**
|
||||
push:
|
||||
branches:
|
||||
@@ -19,7 +18,6 @@ on:
|
||||
- ci/**
|
||||
- composer.*
|
||||
- src/**
|
||||
- phpunit.xml.dist
|
||||
- tests/**
|
||||
|
||||
env:
|
||||
@@ -36,6 +34,7 @@ jobs:
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3.7"
|
||||
@@ -107,11 +106,12 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3.7"
|
||||
postgres-version:
|
||||
- "15"
|
||||
- "17"
|
||||
extension:
|
||||
- pdo_pgsql
|
||||
- pgsql
|
||||
@@ -180,12 +180,13 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3.7"
|
||||
- "4@dev"
|
||||
mariadb-version:
|
||||
- "10.9"
|
||||
- "11.4"
|
||||
extension:
|
||||
- "mysqli"
|
||||
- "pdo_mysql"
|
||||
@@ -194,11 +195,11 @@ jobs:
|
||||
mariadb:
|
||||
image: "mariadb:${{ matrix.mariadb-version }}"
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: "doctrine_tests"
|
||||
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: yes
|
||||
MARIADB_DATABASE: "doctrine_tests"
|
||||
|
||||
options: >-
|
||||
--health-cmd "mysqladmin ping --silent"
|
||||
--health-cmd "healthcheck.sh --connect --innodb_initialized"
|
||||
|
||||
ports:
|
||||
- "3306:3306"
|
||||
@@ -246,6 +247,7 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3.7"
|
||||
@@ -319,6 +321,8 @@ jobs:
|
||||
upload_coverage:
|
||||
name: "Upload coverage to Codecov"
|
||||
runs-on: "ubuntu-22.04"
|
||||
# Only run on PRs from forks
|
||||
if: "github.event.pull_request.head.repo.full_name != github.repository"
|
||||
needs:
|
||||
- "phpunit-smoke-check"
|
||||
- "phpunit-postgres"
|
||||
@@ -337,7 +341,7 @@ jobs:
|
||||
path: "reports"
|
||||
|
||||
- name: "Upload to Codecov"
|
||||
uses: "codecov/codecov-action@v4"
|
||||
uses: "codecov/codecov-action@v5"
|
||||
with:
|
||||
directory: reports
|
||||
env:
|
||||
|
||||
43
.github/workflows/documentation.yml
vendored
43
.github/workflows/documentation.yml
vendored
@@ -5,45 +5,16 @@ on:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/documentation.yml
|
||||
- docs/**
|
||||
- ".github/workflows/documentation.yml"
|
||||
- "docs/**"
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/documentation.yml
|
||||
- docs/**
|
||||
- ".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.3"
|
||||
|
||||
- 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@v3"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
- name: "Add orphan metadata where needed"
|
||||
run: |
|
||||
printf '%s\n\n%s\n' ":orphan:" "$(cat docs/en/sidebar.rst)" > docs/en/sidebar.rst
|
||||
printf '%s\n\n%s\n' ":orphan:" "$(cat docs/en/reference/installation.rst)" > docs/en/reference/installation.rst
|
||||
|
||||
- name: "Run guides-cli"
|
||||
run: "vendor/bin/guides -vvv --no-progress docs/en 2>&1 | grep -v 'No template found for rendering directive' | ( ! grep WARNING )"
|
||||
documentation:
|
||||
name: "Documentation"
|
||||
uses: "doctrine/.github/.github/workflows/documentation.yml@7.3.0"
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@5.0.1"
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.3.0"
|
||||
secrets:
|
||||
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
|
||||
24
.github/workflows/stale.yml
vendored
Normal file
24
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: 'Close stale pull requests'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
stale-pr-message: >
|
||||
There hasn't been any activity on this pull request in the past 90 days, so
|
||||
it has been marked as stale and it will be closed automatically if no
|
||||
further activity occurs in the next 7 days.
|
||||
|
||||
If you want to continue working on it, please leave a comment.
|
||||
|
||||
close-pr-message: >
|
||||
This pull request was closed due to inactivity.
|
||||
|
||||
days-before-stale: -1
|
||||
days-before-pr-stale: 90
|
||||
days-before-pr-close: 7
|
||||
35
.github/workflows/static-analysis.yml
vendored
35
.github/workflows/static-analysis.yml
vendored
@@ -9,7 +9,6 @@ on:
|
||||
- composer.*
|
||||
- src/**
|
||||
- phpstan*
|
||||
- psalm*
|
||||
- tests/StaticAnalysis/**
|
||||
push:
|
||||
branches:
|
||||
@@ -19,7 +18,6 @@ on:
|
||||
- composer.*
|
||||
- src/**
|
||||
- phpstan*
|
||||
- psalm*
|
||||
- tests/StaticAnalysis/**
|
||||
|
||||
jobs:
|
||||
@@ -43,7 +41,7 @@ jobs:
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
coverage: none
|
||||
php-version: "8.3"
|
||||
php-version: "8.4"
|
||||
tools: cs2pr
|
||||
|
||||
- name: Require specific DBAL version
|
||||
@@ -56,34 +54,3 @@ jobs:
|
||||
|
||||
- name: Run static analysis with phpstan/phpstan
|
||||
run: "vendor/bin/phpstan analyse -c ${{ matrix.config }} --error-format=checkstyle | cs2pr"
|
||||
|
||||
static-analysis-psalm:
|
||||
name: Static Analysis with Psalm
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
dbal-version:
|
||||
- default
|
||||
- 3.8.2
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
coverage: none
|
||||
php-version: "8.3"
|
||||
tools: cs2pr
|
||||
|
||||
- name: Require specific DBAL version
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: Install dependencies with Composer
|
||||
uses: ramsey/composer-install@v3
|
||||
|
||||
- name: Run static analysis with Vimeo Psalm
|
||||
run: vendor/bin/psalm --shepherd
|
||||
|
||||
21
.github/workflows/website-schema.yml
vendored
Normal file
21
.github/workflows/website-schema.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
name: "Website config validation"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- ".doctrine-project.json"
|
||||
- ".github/workflows/website-schema.yml"
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- ".doctrine-project.json"
|
||||
- ".github/workflows/website-schema.yml"
|
||||
|
||||
jobs:
|
||||
json-validate:
|
||||
name: "Validate JSON schema"
|
||||
uses: "doctrine/.github/.github/workflows/website-schema.yml@7.1.0"
|
||||
32
README.md
32
README.md
@@ -1,9 +1,7 @@
|
||||
| [4.0.x][4.0] | [3.2.x][3.2] | [3.1.x][3.1] | [2.20.x][2.20] | [2.19.x][2.19] |
|
||||
| [4.0.x][4.0] | [3.4.x][3.4] | [3.3.x][3.3] | [2.21.x][2.21] | [2.20.x][2.20] |
|
||||
|:------------------------------------------------------:|:------------------------------------------------------:|:------------------------------------------------------:|:--------------------------------------------------------:|:--------------------------------------------------------:|
|
||||
| [![Build status][4.0 image]][4.0] | [![Build status][3.2 image]][3.2] | [![Build status][3.1 image]][3.1] | [![Build status][2.20 image]][2.20] | [![Build status][2.19 image]][2.19] |
|
||||
| [![Coverage Status][4.0 coverage image]][4.0 coverage] | [![Coverage Status][3.2 coverage image]][3.2 coverage] | [![Coverage Status][3.1 coverage image]][3.1 coverage] | [![Coverage Status][2.20 coverage image]][2.20 coverage] | [![Coverage Status][2.19 coverage image]][2.19 coverage] |
|
||||
|
||||
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
|
||||
| [![Build status][4.0 image]][4.0] | [![Build status][3.4 image]][3.4] | [![Build status][3.3 image]][3.3] | [![Build status][2.21 image]][2.21] | [![Build status][2.20 image]][2.20] |
|
||||
| [![Coverage Status][4.0 coverage image]][4.0 coverage] | [![Coverage Status][3.4 coverage image]][3.4 coverage] | [![Coverage Status][3.3 coverage image]][3.3 coverage] | [![Coverage Status][2.21 coverage image]][2.21 coverage] | [![Coverage Status][2.20 coverage image]][2.20 coverage] |
|
||||
|
||||
Doctrine ORM is an object-relational mapper for PHP 8.1+ that provides transparent persistence
|
||||
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
|
||||
@@ -22,19 +20,19 @@ without requiring unnecessary code duplication.
|
||||
[4.0]: https://github.com/doctrine/orm/tree/4.0.x
|
||||
[4.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/4.0.x/graph/badge.svg
|
||||
[4.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/4.0.x
|
||||
[3.2 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.2.x
|
||||
[3.2]: https://github.com/doctrine/orm/tree/3.2.x
|
||||
[3.2 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.2.x/graph/badge.svg
|
||||
[3.2 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.2.x
|
||||
[3.1 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.1.x
|
||||
[3.1]: https://github.com/doctrine/orm/tree/3.1.x
|
||||
[3.1 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.1.x/graph/badge.svg
|
||||
[3.1 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.1.x
|
||||
[3.4 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.4.x
|
||||
[3.4]: https://github.com/doctrine/orm/tree/3.4.x
|
||||
[3.4 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.4.x/graph/badge.svg
|
||||
[3.4 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.4.x
|
||||
[3.3 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.3.x
|
||||
[3.3]: https://github.com/doctrine/orm/tree/3.3.x
|
||||
[3.3 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.3.x/graph/badge.svg
|
||||
[3.3 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.3.x
|
||||
[2.21 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.21.x
|
||||
[2.21]: https://github.com/doctrine/orm/tree/2.21.x
|
||||
[2.21 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.21.x/graph/badge.svg
|
||||
[2.21 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.21.x
|
||||
[2.20 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.20.x
|
||||
[2.20]: https://github.com/doctrine/orm/tree/2.20.x
|
||||
[2.20 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.20.x/graph/badge.svg
|
||||
[2.20 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.20.x
|
||||
[2.19 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.19.x
|
||||
[2.19]: https://github.com/doctrine/orm/tree/2.19.x
|
||||
[2.19 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.19.x/graph/badge.svg
|
||||
[2.19 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.19.x
|
||||
|
||||
95
UPGRADE.md
95
UPGRADE.md
@@ -1,3 +1,24 @@
|
||||
# Upgrade to 3.4
|
||||
|
||||
Using the same class several times in a discriminator map is deprecated.
|
||||
In 4.0, this will be an error.
|
||||
|
||||
# Upgrade to 3.3
|
||||
|
||||
## Deprecate `DatabaseDriver`
|
||||
|
||||
The class `Doctrine\ORM\Mapping\Driver\DatabaseDriver` is deprecated without replacement.
|
||||
|
||||
## Add `Doctrine\ORM\Query\OutputWalker` interface, deprecate `Doctrine\ORM\Query\SqlWalker::getExecutor()`
|
||||
|
||||
Output walkers should implement the new `\Doctrine\ORM\Query\OutputWalker` interface and create
|
||||
`Doctrine\ORM\Query\Exec\SqlFinalizer` instances instead of `Doctrine\ORM\Query\Exec\AbstractSqlExecutor`s.
|
||||
The output walker must not base its workings on the query `firstResult`/`maxResult` values, so that the
|
||||
`SqlFinalizer` can be kept in the query cache and used regardless of the actual `firstResult`/`maxResult` values.
|
||||
Any operation dependent on `firstResult`/`maxResult` should take place within the `SqlFinalizer::createExecutor()`
|
||||
method. Details can be found at https://github.com/doctrine/orm/pull/11188.
|
||||
|
||||
|
||||
# Upgrade to 3.2
|
||||
|
||||
## Deprecate the `NotSupported` exception
|
||||
@@ -95,12 +116,44 @@ now they throw an exception.
|
||||
|
||||
## BC BREAK: Partial objects are removed
|
||||
|
||||
- The `PARTIAL` keyword in DQL no longer exists.
|
||||
- `Doctrine\ORM\Query\AST\PartialObjectExpression`is removed.
|
||||
- `Doctrine\ORM\Query\SqlWalker::HINT_PARTIAL` and
|
||||
WARNING: This was relaxed in ORM 3.2 when partial was re-allowed for array-hydration.
|
||||
|
||||
- The `PARTIAL` keyword in DQL no longer exists (reintroduced in ORM 3.2)
|
||||
- `Doctrine\ORM\Query\AST\PartialObjectExpression` is removed. (reintroduced in ORM 3.2)
|
||||
- `Doctrine\ORM\Query\SqlWalker::HINT_PARTIAL` (reintroduced in ORM 3.2) and
|
||||
`Doctrine\ORM\Query::HINT_FORCE_PARTIAL_LOAD` are removed.
|
||||
- `Doctrine\ORM\EntityManager*::getPartialReference()` is removed.
|
||||
|
||||
## BC BREAK: Enforce ArrayCollection Type on `\Doctrine\ORM\QueryBuilder::setParameters(ArrayCollection $parameters)`
|
||||
|
||||
The argument $parameters can no longer be a key=>value array. Only ArrayCollection types are allowed.
|
||||
|
||||
### Before
|
||||
|
||||
```php
|
||||
$qb = $em->createQueryBuilder()
|
||||
->select('u')
|
||||
->from('User', 'u')
|
||||
->where('u.id = :user_id1 OR u.id = :user_id2')
|
||||
->setParameters(array(
|
||||
'user_id1' => 1,
|
||||
'user_id2' => 2
|
||||
));
|
||||
```
|
||||
|
||||
### After
|
||||
|
||||
```php
|
||||
$qb = $em->createQueryBuilder()
|
||||
->select('u')
|
||||
->from('User', 'u')
|
||||
->where('u.id = :user_id1 OR u.id = :user_id2')
|
||||
->setParameters(new ArrayCollection(array(
|
||||
new Parameter('user_id1', 1),
|
||||
new Parameter('user_id2', 2)
|
||||
)));
|
||||
```
|
||||
|
||||
## BC BREAK: `Doctrine\ORM\Persister\Entity\EntityPersister::executeInserts()` return type changed to `void`
|
||||
|
||||
Implementors should adapt to the new signature, and should call
|
||||
@@ -723,6 +776,42 @@ following classes and methods:
|
||||
|
||||
Use `toIterable()` instead.
|
||||
|
||||
# Upgrade to 2.20
|
||||
|
||||
## Add `Doctrine\ORM\Query\OutputWalker` interface, deprecate `Doctrine\ORM\Query\SqlWalker::getExecutor()`
|
||||
|
||||
Output walkers should implement the new `\Doctrine\ORM\Query\OutputWalker` interface and create
|
||||
`Doctrine\ORM\Query\Exec\SqlFinalizer` instances instead of `Doctrine\ORM\Query\Exec\AbstractSqlExecutor`s.
|
||||
The output walker must not base its workings on the query `firstResult`/`maxResult` values, so that the
|
||||
`SqlFinalizer` can be kept in the query cache and used regardless of the actual `firstResult`/`maxResult` values.
|
||||
Any operation dependent on `firstResult`/`maxResult` should take place within the `SqlFinalizer::createExecutor()`
|
||||
method. Details can be found at https://github.com/doctrine/orm/pull/11188.
|
||||
|
||||
## Explictly forbid property hooks
|
||||
|
||||
Property hooks are not supported yet by Doctrine ORM. Until support is added,
|
||||
they are explicitly forbidden because the support would result in a breaking
|
||||
change in behavior.
|
||||
|
||||
Progress on this is tracked at https://github.com/doctrine/orm/issues/11624 .
|
||||
|
||||
## PARTIAL DQL syntax is undeprecated
|
||||
|
||||
Use of the PARTIAL keyword is not deprecated anymore in DQL, because we will be
|
||||
able to support PARTIAL objects with PHP 8.4 Lazy Objects and
|
||||
Symfony/VarExporter in a better way. When we decided to remove this feature
|
||||
these two abstractions did not exist yet.
|
||||
|
||||
WARNING: If you want to upgrade to 3.x and still use PARTIAL keyword in DQL
|
||||
with array or object hydrators, then you have to directly migrate to ORM 3.3.x or higher.
|
||||
PARTIAL keyword in DQL is not available in 3.0, 3.1 and 3.2 of ORM.
|
||||
|
||||
## Deprecate `\Doctrine\ORM\Query\Parser::setCustomOutputTreeWalker()`
|
||||
|
||||
Use the `\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER` query hint to set the output walker
|
||||
class instead of setting it through the `\Doctrine\ORM\Query\Parser::setCustomOutputTreeWalker()` method
|
||||
on the parser instance.
|
||||
|
||||
# Upgrade to 2.19
|
||||
|
||||
## Deprecate calling `ClassMetadata::getAssociationMappedByTargetField()` with the owning side of an association
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
@@ -19,6 +24,7 @@
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -27,7 +33,7 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<source>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</include>
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
@@ -19,6 +24,7 @@
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -27,7 +33,7 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<source>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</include>
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
@@ -16,6 +21,7 @@
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -24,7 +30,7 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<source>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</include>
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
@@ -14,6 +19,7 @@
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -22,7 +28,7 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<source>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</include>
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
@@ -16,6 +21,7 @@
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -24,7 +30,7 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<source>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</include>
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
@@ -14,6 +19,7 @@
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -22,7 +28,7 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<source>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</include>
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
@@ -30,20 +31,22 @@
|
||||
"doctrine/inflector": "^1.4 || ^2.0",
|
||||
"doctrine/instantiator": "^1.3 || ^2",
|
||||
"doctrine/lexer": "^3",
|
||||
"doctrine/persistence": "^3.3.1",
|
||||
"doctrine/persistence": "^3.3.1 || ^4",
|
||||
"psr/cache": "^1 || ^2 || ^3",
|
||||
"symfony/console": "^5.4 || ^6.0 || ^7.0",
|
||||
"symfony/var-exporter": "^6.3.9 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^12.0",
|
||||
"doctrine/coding-standard": "^13.0",
|
||||
"phpbench/phpbench": "^1.0",
|
||||
"phpstan/phpstan": "1.11.1",
|
||||
"phpdocumentor/guides-cli": "^1.4",
|
||||
"phpstan/extension-installer": "^1.4",
|
||||
"phpstan/phpstan": "2.0.3",
|
||||
"phpstan/phpstan-deprecation-rules": "^2",
|
||||
"phpunit/phpunit": "^10.4.0",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.7.2",
|
||||
"symfony/cache": "^5.4 || ^6.2 || ^7.0",
|
||||
"vimeo/psalm": "5.24.0"
|
||||
"squizlabs/php_codesniffer": "3.12.0",
|
||||
"symfony/cache": "^5.4 || ^6.2 || ^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Provides support for XSD validation for XML mapping files",
|
||||
|
||||
3
docs/.gitignore
vendored
Normal file
3
docs/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
composer.lock
|
||||
vendor/
|
||||
build/
|
||||
24
docs/Makefile
Normal file
24
docs/Makefile
Normal file
@@ -0,0 +1,24 @@
|
||||
# Makefile for Doctrine ORM documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
DOCOPTS =
|
||||
BUILD = vendor/bin/guides
|
||||
BUILDDIR = build
|
||||
|
||||
# Internal variables.
|
||||
ALLGUIDESOPTS = $(DOCOPTS) en/
|
||||
|
||||
.PHONY: help clean html
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
|
||||
clean:
|
||||
-rm -rf ./$(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(BUILD) $(ALLGUIDESOPTS) --output=$(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
@@ -1,18 +1,22 @@
|
||||
# Doctrine ORM Documentation
|
||||
|
||||
The documentation is written in [ReStructured Text](https://docutils.sourceforge.io/rst.html).
|
||||
|
||||
## How to Generate:
|
||||
Using Ubuntu 14.04 LTS:
|
||||
|
||||
1. Run ./bin/install-dependencies.sh
|
||||
2. Run ./bin/generate-docs.sh
|
||||
In the `docs/` folder, run
|
||||
|
||||
It will generate the documentation into the build directory of the checkout.
|
||||
composer update
|
||||
|
||||
Then compile the documentation with:
|
||||
|
||||
## Theme issues
|
||||
make html
|
||||
|
||||
If you get a "Theme error", check if the `en/_theme` subdirectory is empty,
|
||||
in which case you will need to run:
|
||||
This will generate the documentation into the `build` subdirectory.
|
||||
|
||||
1. git submodule init
|
||||
2. git submodule update
|
||||
To browse the documentation, you need to run a webserver:
|
||||
|
||||
cd build/html
|
||||
php -S localhost:8000
|
||||
|
||||
Now the documentation is available at [http://localhost:8000](http://localhost:8000).
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
EXECPATH=`dirname $0`
|
||||
cd $EXECPATH
|
||||
cd ..
|
||||
|
||||
rm build -Rf
|
||||
sphinx-build en build
|
||||
|
||||
sphinx-build -b latex en build/pdf
|
||||
rubber --into build/pdf --pdf build/pdf/Doctrine2ORM.tex
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/bash
|
||||
sudo apt-get update && sudo apt-get install -y python2.7 python-sphinx python-pygments
|
||||
10
docs/composer.json
Normal file
10
docs/composer.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "doctrine/orm-docs",
|
||||
"description": "Documentation for the Object-Relational Mapper\"",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"phpdocumentor/guides-cli": "1.7.1",
|
||||
"phpdocumentor/filesystem": "1.7.1"
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Doctrine2ORM.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Doctrine2ORM.qhc"
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
|
||||
"run these through (pdf)latex."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
@@ -1,91 +0,0 @@
|
||||
#Copyright (c) 2010 Fabien Potencier
|
||||
#
|
||||
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
#of this software and associated documentation files (the "Software"), to deal
|
||||
#in the Software without restriction, including without limitation the rights
|
||||
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
#copies of the Software, and to permit persons to whom the Software is furnished
|
||||
#to do so, subject to the following conditions:
|
||||
#
|
||||
#The above copyright notice and this permission notice shall be included in all
|
||||
#copies or substantial portions of the Software.
|
||||
#
|
||||
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
#THE SOFTWARE.
|
||||
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
from docutils import nodes
|
||||
from string import upper
|
||||
|
||||
class configurationblock(nodes.General, nodes.Element):
|
||||
pass
|
||||
|
||||
class ConfigurationBlock(Directive):
|
||||
has_content = True
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {}
|
||||
formats = {
|
||||
'html': 'HTML',
|
||||
'xml': 'XML',
|
||||
'php': 'PHP',
|
||||
'jinja': 'Twig',
|
||||
'html+jinja': 'Twig',
|
||||
'jinja+html': 'Twig',
|
||||
'php+html': 'PHP',
|
||||
'html+php': 'PHP',
|
||||
'ini': 'INI',
|
||||
}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
|
||||
node = nodes.Element()
|
||||
node.document = self.state.document
|
||||
self.state.nested_parse(self.content, self.content_offset, node)
|
||||
|
||||
entries = []
|
||||
for i, child in enumerate(node):
|
||||
if isinstance(child, nodes.literal_block):
|
||||
# add a title (the language name) before each block
|
||||
#targetid = "configuration-block-%d" % env.new_serialno('configuration-block')
|
||||
#targetnode = nodes.target('', '', ids=[targetid])
|
||||
#targetnode.append(child)
|
||||
|
||||
innernode = nodes.emphasis(self.formats[child['language']], self.formats[child['language']])
|
||||
|
||||
para = nodes.paragraph()
|
||||
para += [innernode, child]
|
||||
|
||||
entry = nodes.list_item('')
|
||||
entry.append(para)
|
||||
entries.append(entry)
|
||||
|
||||
resultnode = configurationblock()
|
||||
resultnode.append(nodes.bullet_list('', *entries))
|
||||
|
||||
return [resultnode]
|
||||
|
||||
def visit_configurationblock_html(self, node):
|
||||
self.body.append(self.starttag(node, 'div', CLASS='configuration-block'))
|
||||
|
||||
def depart_configurationblock_html(self, node):
|
||||
self.body.append('</div>\n')
|
||||
|
||||
def visit_configurationblock_latex(self, node):
|
||||
pass
|
||||
|
||||
def depart_configurationblock_latex(self, node):
|
||||
pass
|
||||
|
||||
def setup(app):
|
||||
app.add_node(configurationblock,
|
||||
html=(visit_configurationblock_html, depart_configurationblock_html),
|
||||
latex=(visit_configurationblock_latex, depart_configurationblock_latex))
|
||||
app.add_directive('configuration-block', ConfigurationBlock)
|
||||
Submodule docs/en/_theme deleted from 6f1bc8bead
@@ -352,7 +352,7 @@ the database using a FOR UPDATE.
|
||||
use Bank\Entities\Account;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
|
||||
$account = $em->find(Account::class, $accId, LockMode::PESSIMISTIC_READ);
|
||||
$account = $em->find(Account::class, $accId, LockMode::PESSIMISTIC_WRITE);
|
||||
|
||||
Keeping Updates and Deletes in Sync
|
||||
-----------------------------------
|
||||
|
||||
@@ -232,6 +232,33 @@ vendors SQL parser to show us further errors in the parsing
|
||||
process, for example if the Unit would not be one of the supported
|
||||
values by MySql.
|
||||
|
||||
Typed functions
|
||||
---------------
|
||||
By default, result of custom functions is fetched as-is from the database driver.
|
||||
If you want to be sure that the type is always the same, then your custom function needs to
|
||||
implement ``Doctrine\ORM\Query\AST\TypedExpression``. Then, the result is wired
|
||||
through ``Doctrine\DBAL\Types\Type::convertToPhpValue()`` of the ``Type`` returned in ``getReturnType()``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\AST\TypedExpression;
|
||||
|
||||
class DateDiff extends FunctionNode implements TypedExpression
|
||||
{
|
||||
// ...
|
||||
|
||||
public function getReturnType(): Type
|
||||
{
|
||||
return Type::getType(Types::INTEGER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Conclusion
|
||||
----------
|
||||
|
||||
|
||||
44
docs/en/cookbook/generated-columns.rst
Normal file
44
docs/en/cookbook/generated-columns.rst
Normal file
@@ -0,0 +1,44 @@
|
||||
Generated Columns
|
||||
=================
|
||||
|
||||
Generated columns, sometimes also called virtual columns, are populated by
|
||||
the database engine itself. They are a tool for performance optimization, to
|
||||
avoid calculating a value on each query.
|
||||
|
||||
You can define generated columns on entities and have Doctrine map the values
|
||||
to your entity.
|
||||
|
||||
Declaring a generated column
|
||||
----------------------------
|
||||
|
||||
There is no explicit mapping instruction for generated columns. Instead, you
|
||||
specify that the column should not be written to, and define a custom column
|
||||
definition.
|
||||
|
||||
.. literalinclude:: generated-columns/Person.php
|
||||
:language: php
|
||||
|
||||
* ``insertable``, ``updatable``: Setting these to false tells Doctrine to never
|
||||
write this column - writing to a generated column would result in an error
|
||||
from the database.
|
||||
* ``columnDefinition``: We specify the full DDL to create the column. To allow
|
||||
to use database specific features, this attribute does not use Doctrine Query
|
||||
Language but native SQL. Note that you need to reference columns by their
|
||||
database name (either explicitly set in the mapping or per the current
|
||||
:doc:`naming strategy <../reference/namingstrategy>`).
|
||||
Be aware that specifying a column definition makes the ``SchemaTool``
|
||||
completely ignore all other configuration for this column. See also
|
||||
:ref:`#[Column] <attrref_column>`
|
||||
* ``generated``: Specifying that this column is always generated tells Doctrine
|
||||
to update the field on the entity with the value from the database after
|
||||
every write operation.
|
||||
|
||||
Advanced example: Extracting a value from a JSON structure
|
||||
----------------------------------------------------------
|
||||
|
||||
Lets assume we have an entity that stores a blogpost as structured JSON.
|
||||
To avoid extracting all titles on the fly when listing the posts, we create a
|
||||
generated column with the field.
|
||||
|
||||
.. literalinclude:: generated-columns/Article.php
|
||||
:language: php
|
||||
33
docs/en/cookbook/generated-columns/Article.php
Normal file
33
docs/en/cookbook/generated-columns/Article.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity]
|
||||
class Article
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private int $id;
|
||||
|
||||
/**
|
||||
* When working with Postgres, it is recommended to use the jsonb
|
||||
* format for better performance.
|
||||
*/
|
||||
#[ORM\Column(options: ['jsonb' => true])]
|
||||
private array $content;
|
||||
|
||||
/**
|
||||
* Because we specify NOT NULL, inserting will fail if the content does
|
||||
* not have a string in the title field.
|
||||
*/
|
||||
#[ORM\Column(
|
||||
insertable: false,
|
||||
updatable: false,
|
||||
columnDefinition: "VARCHAR(255) generated always as (content->>'title') stored NOT NULL",
|
||||
generated: 'ALWAYS',
|
||||
)]
|
||||
private string $title;
|
||||
}
|
||||
24
docs/en/cookbook/generated-columns/Person.php
Normal file
24
docs/en/cookbook/generated-columns/Person.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity]
|
||||
class Person
|
||||
{
|
||||
#[ORM\Column(type: 'string')]
|
||||
private string $firstName;
|
||||
|
||||
#[ORM\Column(type: 'string', name: 'name')]
|
||||
private string $lastName;
|
||||
|
||||
#[ORM\Column(
|
||||
type: 'string',
|
||||
insertable: false,
|
||||
updatable: false,
|
||||
columnDefinition: "VARCHAR(255) GENERATED ALWAYS AS (concat(firstName, ' ', name) stored NOT NULL",
|
||||
generated: 'ALWAYS',
|
||||
)]
|
||||
private string $fullName;
|
||||
}
|
||||
@@ -73,6 +73,8 @@ Advanced Topics
|
||||
* :doc:`TypedFieldMapper <reference/typedfieldmapper>`
|
||||
* :doc:`Improving Performance <reference/improving-performance>`
|
||||
* :doc:`Caching <reference/caching>`
|
||||
* :doc:`Partial Hydration <reference/partial-hydration>`
|
||||
* :doc:`Partial Objects <reference/partial-objects>`
|
||||
* :doc:`Change Tracking Policies <reference/change-tracking-policies>`
|
||||
* :doc:`Best Practices <reference/best-practices>`
|
||||
* :doc:`Metadata Drivers <reference/metadata-drivers>`
|
||||
@@ -100,6 +102,7 @@ Cookbook
|
||||
|
||||
* **Patterns**:
|
||||
:doc:`Aggregate Fields <cookbook/aggregate-fields>` \|
|
||||
:doc:`Generated/Virtual Columns <cookbook/generated-columns>` \|
|
||||
:doc:`Decorator Pattern <cookbook/decorator-pattern>` \|
|
||||
:doc:`Strategy Pattern <cookbook/strategy-cookbook-introduction>`
|
||||
|
||||
@@ -119,4 +122,5 @@ Cookbook
|
||||
|
||||
* **Custom Datatypes**
|
||||
:doc:`MySQL Enums <cookbook/mysql-enums>`
|
||||
:doc:`Custom Mapping Types <cookbook/custom-mapping-types>`
|
||||
:doc:`Advanced Field Value Conversion <cookbook/advanced-field-value-conversion-using-custom-mapping-types>`
|
||||
|
||||
113
docs/en/make.bat
113
docs/en/make.bat
@@ -1,113 +0,0 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
set SPHINXBUILD=sphinx-build
|
||||
set BUILDDIR=_build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||
del /q /s %BUILDDIR%\*
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Doctrine2ORM.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Doctrine2ORM.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in %BUILDDIR%/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
||||
@@ -71,8 +71,8 @@ Configuration Options
|
||||
The following sections describe all the configuration options
|
||||
available on a ``Doctrine\ORM\Configuration`` instance.
|
||||
|
||||
Proxy Directory (***REQUIRED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Proxy Directory (**REQUIRED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -85,8 +85,8 @@ classes. For a detailed explanation on proxy classes and how they
|
||||
are used in Doctrine, refer to the "Proxy Objects" section further
|
||||
down.
|
||||
|
||||
Proxy Namespace (***REQUIRED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Proxy Namespace (**REQUIRED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -98,8 +98,8 @@ Gets or sets the namespace to use for generated proxy classes. For
|
||||
a detailed explanation on proxy classes and how they are used in
|
||||
Doctrine, refer to the "Proxy Objects" section further down.
|
||||
|
||||
Metadata Driver (***REQUIRED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Metadata Driver (**REQUIRED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -139,8 +139,8 @@ accept either a single directory as a string or an array of
|
||||
directories. With this feature a single driver can support multiple
|
||||
directories of Entities.
|
||||
|
||||
Metadata Cache (***RECOMMENDED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Metadata Cache (**RECOMMENDED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -161,8 +161,8 @@ For development you should use an array cache like
|
||||
``Symfony\Component\Cache\Adapter\ArrayAdapter``
|
||||
which only caches data on a per-request basis.
|
||||
|
||||
Query Cache (***RECOMMENDED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Query Cache (**RECOMMENDED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -184,8 +184,8 @@ For development you should use an array cache like
|
||||
``Symfony\Component\Cache\Adapter\ArrayAdapter``
|
||||
which only caches data on a per-request basis.
|
||||
|
||||
SQL Logger (***Optional***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
SQL Logger (**Optional**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -197,8 +197,8 @@ Gets or sets the logger to use for logging all SQL statements
|
||||
executed by Doctrine. The logger class must implement the
|
||||
deprecated ``Doctrine\DBAL\Logging\SQLLogger`` interface.
|
||||
|
||||
Auto-generating Proxy Classes (***OPTIONAL***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Auto-generating Proxy Classes (**OPTIONAL**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Proxy classes can either be generated manually through the Doctrine
|
||||
Console or automatically at runtime by Doctrine. The configuration
|
||||
@@ -441,7 +441,7 @@ correctly if sub-namespaces use different metadata driver
|
||||
implementations.
|
||||
|
||||
|
||||
Default Repository (***OPTIONAL***)
|
||||
Default Repository (**OPTIONAL**)
|
||||
-----------------------------------
|
||||
|
||||
Specifies the FQCN of a subclass of the EntityRepository.
|
||||
@@ -456,7 +456,7 @@ That will be available for all entities without a custom repository class.
|
||||
The default value is ``Doctrine\ORM\EntityRepository``.
|
||||
Any repository class must be a subclass of EntityRepository otherwise you got an ORMException
|
||||
|
||||
Ignoring entities (***OPTIONAL***)
|
||||
Ignoring entities (**OPTIONAL**)
|
||||
-----------------------------------
|
||||
|
||||
Specifies the Entity FQCNs to ignore.
|
||||
|
||||
@@ -33,14 +33,13 @@ Doctrine ORM is divided into four main packages.
|
||||
- ORM (depends on DBAL+Persistence+Collections)
|
||||
|
||||
This manual mainly covers the ORM package, sometimes touching parts
|
||||
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...
|
||||
of the underlying DBAL and Persistence packages. The Doctrine codebase
|
||||
is split into these packages for a few reasons:
|
||||
|
||||
|
||||
- ...make things more maintainable and decoupled
|
||||
- ...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
|
||||
- to make things more maintainable and decoupled
|
||||
- to allow you to use the code in Doctrine Persistence and Collections without the ORM or DBAL
|
||||
- to allow you to use the DBAL without the ORM
|
||||
|
||||
Collection, Event Manager and Persistence
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -903,8 +903,7 @@ defaults to "id", just as in one-to-one or many-to-one mappings.
|
||||
|
||||
Additionally, when using typed properties with Doctrine 2.9 or newer
|
||||
you can skip ``targetEntity`` in ``ManyToOne`` and ``OneToOne``
|
||||
associations as they will be set based on type. Also ``nullable``
|
||||
attribute on ``JoinColumn`` will be inherited from PHP type. So that:
|
||||
associations as they will be set based on type. So that:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
@@ -931,7 +930,7 @@ Is essentially the same as following:
|
||||
<?php
|
||||
/** One Product has One Shipment. */
|
||||
#[OneToOne(targetEntity: Shipment::class)]
|
||||
#[JoinColumn(name: 'shipment_id', referencedColumnName: 'id', nullable: false)]
|
||||
#[JoinColumn(name: 'shipment_id', referencedColumnName: 'id')]
|
||||
private Shipment $shipment;
|
||||
|
||||
.. code-block:: annotation
|
||||
@@ -940,7 +939,7 @@ Is essentially the same as following:
|
||||
/**
|
||||
* One Product has One Shipment.
|
||||
* @OneToOne(targetEntity="Shipment")
|
||||
* @JoinColumn(name="shipment_id", referencedColumnName="id", nullable=false)
|
||||
* @JoinColumn(name="shipment_id", referencedColumnName="id")
|
||||
*/
|
||||
private Shipment $shipment;
|
||||
|
||||
@@ -949,7 +948,7 @@ Is essentially the same as following:
|
||||
<doctrine-mapping>
|
||||
<entity class="Product">
|
||||
<one-to-one field="shipment" target-entity="Shipment">
|
||||
<join-column name="shipment_id" referenced-column-name="id" nulable=false />
|
||||
<join-column name="shipment_id" referenced-column-name="id" nullable=false />
|
||||
</one-to-one>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
@@ -15,7 +15,7 @@ Index
|
||||
- :ref:`#[AttributeOverride] <attrref_attributeoverride>`
|
||||
- :ref:`#[Column] <attrref_column>`
|
||||
- :ref:`#[Cache] <attrref_cache>`
|
||||
- :ref:`#[ChangeTrackingPolicy <attrref_changetrackingpolicy>`
|
||||
- :ref:`#[ChangeTrackingPolicy] <attrref_changetrackingpolicy>`
|
||||
- :ref:`#[CustomIdGenerator] <attrref_customidgenerator>`
|
||||
- :ref:`#[DiscriminatorColumn] <attrref_discriminatorcolumn>`
|
||||
- :ref:`#[DiscriminatorMap] <attrref_discriminatormap>`
|
||||
@@ -214,12 +214,15 @@ Optional parameters:
|
||||
- ``check``: Adds a check constraint type to the column (might not
|
||||
be supported by all vendors).
|
||||
|
||||
- **columnDefinition**: DDL SQL snippet that starts after the column
|
||||
- **columnDefinition**: Specify the DDL SQL snippet that starts after the column
|
||||
name and specifies the complete (non-portable!) column definition.
|
||||
This attribute allows to make use of advanced RMDBS features.
|
||||
However you should make careful use of this feature and the
|
||||
consequences. ``SchemaTool`` will not detect changes on the column correctly
|
||||
anymore if you use ``columnDefinition``.
|
||||
However, as this needs to be specified in the DDL native to the database,
|
||||
the resulting schema changes are no longer portable. If you specify a
|
||||
``columnDefinition``, the ``SchemaTool`` ignores all other attributes
|
||||
that are normally used to build the definition DDL. Changes to the
|
||||
``columnDefinition`` are not detected, you will need to manually create a
|
||||
migration to apply changes.
|
||||
|
||||
Additionally you should remember that the ``type``
|
||||
attribute still handles the conversion between PHP and Database
|
||||
@@ -262,10 +265,11 @@ Examples:
|
||||
)]
|
||||
protected $loginCount;
|
||||
|
||||
// MySQL example: full_name char(41) GENERATED ALWAYS AS (concat(firstname,' ',lastname)),
|
||||
// columnDefinition is raw SQL, not DQL. This example works for MySQL:
|
||||
#[Column(
|
||||
type: "string",
|
||||
name: "user_fullname",
|
||||
columnDefinition: "VARCHAR(255) GENERATED ALWAYS AS (concat(firstname,' ',lastname))",
|
||||
insertable: false,
|
||||
updatable: false
|
||||
)]
|
||||
@@ -366,7 +370,7 @@ Optional parameters:
|
||||
|
||||
- **type**: By default this is string.
|
||||
- **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.
|
||||
- **columnDefinition**: Allows to override how the column is generated. See the "columnDefinition" attribute on :ref:`#[Column] <attrref_column>`
|
||||
- **enumType**: By default this is `null`. Allows to map discriminatorColumn value to PHP enum
|
||||
- **options**: See "options" attribute on :ref:`#[Column] <attrref_column>`.
|
||||
|
||||
@@ -677,8 +681,10 @@ Optional parameters:
|
||||
- **onDelete**: Cascade Action (Database-level)
|
||||
- **columnDefinition**: DDL SQL snippet that starts after the column
|
||||
name and specifies the complete (non-portable!) column definition.
|
||||
This attribute enables the use of advanced RMDBS features. Using
|
||||
this attribute on ``#[JoinColumn]`` is necessary if you need slightly
|
||||
This attribute enables the use of advanced RMDBS features. Note that you
|
||||
need to reference columns by their database name (either explicitly set in
|
||||
the mapping or per the current :doc:`naming strategy <namingstrategy>`).
|
||||
Using this attribute on ``#[JoinColumn]`` is necessary if you need
|
||||
different column definitions for joining columns, for example
|
||||
regarding NULL/NOT NULL defaults. However by default a
|
||||
"columnDefinition" attribute on :ref:`#[Column] <attrref_column>` also sets
|
||||
@@ -1133,7 +1139,7 @@ Marker attribute that defines a specified column as version attribute used in
|
||||
an :ref:`optimistic locking <transactions-and-concurrency_optimistic-locking>`
|
||||
scenario. It only works on :ref:`#[Column] <attrref_column>` attributes that have
|
||||
the type ``integer`` or ``datetime``. Setting ``#[Version]`` on a property with
|
||||
:ref:`#[Id <attrref_id>` is not supported.
|
||||
:ref:`#[Id] <attrref_id>` is not supported.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -167,6 +167,7 @@ Here is a complete list of ``Column``s attributes (all optional):
|
||||
- ``nullable`` (default: ``false``): Whether the column is nullable.
|
||||
- ``insertable`` (default: ``true``): Whether the column should be inserted.
|
||||
- ``updatable`` (default: ``true``): Whether the column should be updated.
|
||||
- ``generated`` (default: ``null``): Whether the generated strategy should be ``'NEVER'``, ``'INSERT'`` and ``ALWAYS``.
|
||||
- ``enumType`` (requires PHP 8.1 and ``doctrine/orm`` 2.11): The PHP enum class name to convert the database value into.
|
||||
- ``precision`` (default: 0): The precision for a decimal (exact numeric) column
|
||||
(applies only for decimal column),
|
||||
|
||||
@@ -523,6 +523,34 @@ when the DQL is switched to an arbitrary join.
|
||||
- HAVING is applied to the results of a query after
|
||||
aggregation (GROUP BY)
|
||||
|
||||
|
||||
Partial Hydration Syntax
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
By default when you run a DQL query in Doctrine and select only a
|
||||
subset of the fields for a given entity, you do not receive objects
|
||||
back. Instead, you receive only arrays as a flat rectangular result
|
||||
set, similar to how you would if you were just using SQL directly
|
||||
and joining some data.
|
||||
|
||||
If you want to select partial objects or fields in array hydration you can use the ``partial``
|
||||
DQL keyword:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT partial u.{id, username} FROM CmsUser u');
|
||||
$users = $query->getResult(); // array of partially loaded CmsUser objects
|
||||
|
||||
You can use the partial syntax when joining as well:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT partial u.{id, username}, partial a.{id, name} FROM CmsUser u JOIN u.articles a');
|
||||
$usersArray = $query->getArrayResult(); // array of partially loaded CmsUser and CmsArticle fields
|
||||
$users = $query->getResult(); // array of partially loaded CmsUser objects
|
||||
|
||||
"NEW" Operator Syntax
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -560,7 +588,91 @@ And then use the ``NEW`` DQL keyword :
|
||||
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, a.city, SUM(o.value)) FROM Customer c JOIN c.email e JOIN c.address a JOIN c.orders o GROUP BY c');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
Note that you can only pass scalar expressions to the constructor.
|
||||
You can also nest several DTO :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class CustomerDTO
|
||||
{
|
||||
public function __construct(string $name, string $email, AddressDTO $address, string|null $value = null)
|
||||
{
|
||||
// Bind values to the object properties.
|
||||
}
|
||||
}
|
||||
|
||||
class AddressDTO
|
||||
{
|
||||
public function __construct(string $street, string $city, string $zip)
|
||||
{
|
||||
// Bind values to the object properties.
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, NEW AddressDTO(a.street, a.city, a.zip)) FROM Customer c JOIN c.email e JOIN c.address a');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
Note that you can only pass scalar expressions or other Data Transfer Objects to the constructor.
|
||||
|
||||
If you use your data transfer objects for multiple queries, and you would rather not have to
|
||||
specify arguments that precede the ones you are really interested in, you can use named arguments.
|
||||
|
||||
Consider the following DTO, which uses optional arguments:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
class CustomerDTO
|
||||
{
|
||||
public function __construct(
|
||||
public string|null $name = null,
|
||||
public string|null $email = null,
|
||||
public string|null $city = null,
|
||||
public mixed|null $value = null,
|
||||
public AddressDTO|null $address = null,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
You can specify arbitrary arguments in an arbitrary order by using the named argument syntax, and the ORM will try to match argument names with the selected column names.
|
||||
The syntax relies on the NAMED keyword, like so:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT NEW NAMED CustomerDTO(a.city, c.name) FROM Customer c JOIN c.address a');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
// CustomerDTO => {name : 'SMITH', email: null, city: 'London', value: null}
|
||||
|
||||
ORM will also give precedence to column aliases over column names :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT NEW NAMED CustomerDTO(c.name, CONCAT(a.city, ' ' , a.zip) AS value) FROM Customer c JOIN c.address a');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
// CustomerDTO => {name : 'DOE', email: null, city: null, value: 'New York 10011'}
|
||||
|
||||
To define a custom name for a DTO constructor argument, you can either alias the column with the ``AS`` keyword.
|
||||
|
||||
The ``NAMED`` keyword must precede all DTO you want to instantiate :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT NEW NAMED CustomerDTO(c.name, NEW NAMED AddressDTO(a.street, a.city, a.zip) AS address) FROM Customer c JOIN c.address a');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
// CustomerDTO => {name : 'DOE', email: null, city: null, value: 'New York 10011'}
|
||||
|
||||
If two arguments have the same name, a ``DuplicateFieldException`` is thrown.
|
||||
If a field cannot be matched with a property name, a ``NoMatchingPropertyException`` is thrown. This typically happens when using functions without aliasing them.
|
||||
|
||||
Using INDEX BY
|
||||
~~~~~~~~~~~~~~
|
||||
@@ -1324,6 +1436,15 @@ exist mostly internal query hints that are not be consumed in
|
||||
userland. However the following few hints are to be used in
|
||||
userland:
|
||||
|
||||
|
||||
- ``Query::HINT_FORCE_PARTIAL_LOAD`` - Allows to hydrate objects
|
||||
although not all their columns are fetched. This query hint can be
|
||||
used to handle memory consumption problems with large result-sets
|
||||
that contain char or binary data. Doctrine has no way of implicitly
|
||||
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>`_)
|
||||
- ``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
|
||||
@@ -1576,10 +1697,12 @@ Select Expressions
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
SelectExpression ::= (IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | "(" Subselect ")" | CaseExpression | NewObjectExpression) [["AS"] ["HIDDEN"] AliasResultVariable]
|
||||
SelectExpression ::= (IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression | NewObjectExpression) [["AS"] ["HIDDEN"] AliasResultVariable]
|
||||
SimpleSelectExpression ::= (StateFieldPathExpression | IdentificationVariable | FunctionDeclaration | AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable]
|
||||
PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
|
||||
PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
|
||||
NewObjectExpression ::= "NEW" AbstractSchemaName "(" NewObjectArg {"," NewObjectArg}* ")"
|
||||
NewObjectArg ::= ScalarExpression | "(" Subselect ")"
|
||||
NewObjectArg ::= (ScalarExpression | "(" Subselect ")" | NewObjectExpression) ["AS" AliasResultVariable]
|
||||
|
||||
Conditional Expressions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -265,7 +265,7 @@ specific to a particular entity class's lifecycle.
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
@@ -16,7 +16,7 @@ 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). They
|
||||
are not query-able, and need not have an ``#[Id]`` property.
|
||||
are not query-able, and do not require an ``#[Id]`` property.
|
||||
|
||||
No database table will be created for a mapped superclass itself,
|
||||
only for entity classes inheriting from it. That implies that a
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
:orphan:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
|
||||
@@ -70,8 +70,8 @@ implements the ``MappingDriver`` interface:
|
||||
/**
|
||||
* Loads the metadata for the specified class into the provided container.
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -82,8 +82,7 @@ implements the ``MappingDriver`` interface:
|
||||
/**
|
||||
* Gets the names of all mapped classes known to this driver.
|
||||
*
|
||||
* @return array<int, string> The names of all mapped classes known to this driver.
|
||||
* @psalm-return list<class-string>
|
||||
* @return list<class-string> The names of all mapped classes known to this driver.
|
||||
*/
|
||||
public function getAllClassNames();
|
||||
|
||||
@@ -91,7 +90,7 @@ implements the ``MappingDriver`` interface:
|
||||
* Returns whether the class with the specified name should have its metadata loaded.
|
||||
* This is only the case if it is either mapped as an Entity or a MappedSuperclass.
|
||||
*
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
15
docs/en/reference/partial-hydration.rst
Normal file
15
docs/en/reference/partial-hydration.rst
Normal file
@@ -0,0 +1,15 @@
|
||||
Partial Hydration
|
||||
=================
|
||||
|
||||
Partial hydration of entities is allowed in the array hydrator, when
|
||||
only a subset of the fields of an entity are loaded from the database
|
||||
and the nested results are still created based on the entity relationship structure.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$users = $em->createQuery("SELECT PARTIAL u.{id,name}, partial a.{id,street} FROM MyApp\Domain\User u JOIN u.addresses a")
|
||||
->getArrayResult();
|
||||
|
||||
This is a useful optimization when you are not interested in all fields of an entity
|
||||
for performance reasons, for example in use-cases for exporting or rendering lots of data.
|
||||
88
docs/en/reference/partial-objects.rst
Normal file
88
docs/en/reference/partial-objects.rst
Normal file
@@ -0,0 +1,88 @@
|
||||
Partial Objects
|
||||
===============
|
||||
|
||||
A partial object is an object whose state is not fully initialized
|
||||
after being reconstituted from the database and that is
|
||||
disconnected from the rest of its data. The following section will
|
||||
describe why partial objects are problematic and what the approach
|
||||
of Doctrine to this problem is.
|
||||
|
||||
.. note::
|
||||
|
||||
The partial object problem in general does not apply to
|
||||
methods or queries where you do not retrieve the query result as
|
||||
objects. Examples are: ``Query#getArrayResult()``,
|
||||
``Query#getScalarResult()``, ``Query#getSingleScalarResult()``,
|
||||
etc.
|
||||
|
||||
.. warning::
|
||||
|
||||
Use of partial objects is tricky. Fields that are not retrieved
|
||||
from the database will not be updated by the UnitOfWork even if they
|
||||
get changed in your objects. You can only promote a partial object
|
||||
to a fully-loaded object by calling ``EntityManager#refresh()``
|
||||
or a DQL query with the refresh flag.
|
||||
|
||||
|
||||
What is the problem?
|
||||
--------------------
|
||||
|
||||
In short, partial objects are problematic because they are usually
|
||||
objects with broken invariants. As such, code that uses these
|
||||
partial objects tends to be very fragile and either needs to "know"
|
||||
which fields or methods can be safely accessed or add checks around
|
||||
every field access or method invocation. The same holds true for
|
||||
the internals, i.e. the method implementations, of such objects.
|
||||
You usually simply assume the state you need in the method is
|
||||
available, after all you properly constructed this object before
|
||||
you pushed it into the database, right? These blind assumptions can
|
||||
quickly lead to null reference errors when working with such
|
||||
partial objects.
|
||||
|
||||
It gets worse with the scenario of an optional association (0..1 to
|
||||
1). When the associated field is NULL, you don't know whether this
|
||||
object does not have an associated object or whether it was simply
|
||||
not loaded when the owning object was loaded from the database.
|
||||
|
||||
These are reasons why many ORMs do not allow partial objects at all
|
||||
and instead you always have to load an object with all its fields
|
||||
(associations being proxied). One secure way to allow partial
|
||||
objects is if the programming language/platform allows the ORM tool
|
||||
to hook deeply into the object and instrument it in such a way that
|
||||
individual fields (not only associations) can be loaded lazily on
|
||||
first access. This is possible in Java, for example, through
|
||||
bytecode instrumentation. In PHP though this is not possible, so
|
||||
there is no way to have "secure" partial objects in an ORM with
|
||||
transparent persistence.
|
||||
|
||||
Doctrine, by default, does not allow partial objects. That means,
|
||||
any query that only selects partial object data and wants to
|
||||
retrieve the result as objects (i.e. ``Query#getResult()``) will
|
||||
raise an exception telling you that partial objects are dangerous.
|
||||
If you want to force a query to return you partial objects,
|
||||
possibly as a performance tweak, you can use the ``partial``
|
||||
keyword as follows:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$q = $em->createQuery("select partial u.{id,name} from MyApp\Domain\User u");
|
||||
|
||||
You can also get a partial reference instead of a proxy reference by
|
||||
calling:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$reference = $em->getPartialReference('MyApp\Domain\User', 1);
|
||||
|
||||
Partial references are objects with only the identifiers set as they
|
||||
are passed to the second argument of the ``getPartialReference()`` method.
|
||||
All other fields are null.
|
||||
|
||||
When should I force partial objects?
|
||||
------------------------------------
|
||||
|
||||
Mainly for optimization purposes, but be careful of premature
|
||||
optimization as partial objects lead to potentially more fragile
|
||||
code.
|
||||
@@ -611,3 +611,21 @@ same query of example 6 written using
|
||||
->add('from', new Expr\From('User', 'u'))
|
||||
->add('where', new Expr\Comparison('u.id', '=', '?1'))
|
||||
->add('orderBy', new Expr\OrderBy('u.name', 'ASC'));
|
||||
|
||||
Binding Parameters to Placeholders
|
||||
----------------------------------
|
||||
|
||||
It is often not necessary to know about the exact placeholder names when
|
||||
building a query. You can use a helper method to bind a value to a placeholder
|
||||
and directly use that placeholder in your query as a return value:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// $qb instanceof QueryBuilder
|
||||
|
||||
$qb->select('u')
|
||||
->from('User', 'u')
|
||||
->where('u.email = ' . $qb->createNamedParameter($userInputEmail))
|
||||
;
|
||||
// SELECT u FROM User u WHERE email = :dcValue1
|
||||
|
||||
@@ -299,7 +299,7 @@ level cache region.
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
@@ -351,7 +351,7 @@ It caches the primary keys of association and cache each element will be cached
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
@@ -88,7 +88,7 @@ requirement.
|
||||
|
||||
A more convenient alternative for explicit transaction demarcation is the use
|
||||
of provided control abstractions in the form of
|
||||
``Connection#transactional($func)`` and ``EntityManager#transactional($func)``.
|
||||
``Connection#transactional($func)`` and ``EntityManager#wrapInTransaction($func)``.
|
||||
When used, these control abstractions ensure that you never forget to rollback
|
||||
the transaction, in addition to the obvious code reduction. An example that is
|
||||
functionally equivalent to the previously shown code looks as follows:
|
||||
@@ -96,21 +96,23 @@ functionally equivalent to the previously shown code looks as follows:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// transactional with Connection instance
|
||||
// $conn instanceof Connection
|
||||
$conn->transactional(function($conn) {
|
||||
// ... do some work
|
||||
$user = new User;
|
||||
$user->setName('George');
|
||||
});
|
||||
|
||||
// transactional with EntityManager instance
|
||||
// $em instanceof EntityManager
|
||||
$em->transactional(function($em) {
|
||||
$em->wrapInTransaction(function($em) {
|
||||
// ... do some work
|
||||
$user = new User;
|
||||
$user->setName('George');
|
||||
$em->persist($user);
|
||||
});
|
||||
|
||||
.. warning::
|
||||
|
||||
For historical reasons, ``EntityManager#transactional($func)`` will return
|
||||
``true`` whenever the return value of ``$func`` is loosely false.
|
||||
Some examples of this include ``array()``, ``"0"``, ``""``, ``0``, and
|
||||
``null``.
|
||||
|
||||
The difference between ``Connection#transactional($func)`` and
|
||||
``EntityManager#transactional($func)`` is that the latter
|
||||
abstraction flushes the ``EntityManager`` prior to transaction
|
||||
|
||||
@@ -102,7 +102,7 @@ How Doctrine Detects Changes
|
||||
----------------------------
|
||||
|
||||
Doctrine is a data-mapper that tries to achieve persistence-ignorance (PI).
|
||||
This means you map php objects into a relational database that don't
|
||||
This means you map PHP objects into a relational database that don't
|
||||
necessarily know about the database at all. A natural question would now be,
|
||||
"how does Doctrine even detect objects have changed?".
|
||||
|
||||
|
||||
@@ -736,6 +736,35 @@ methods:
|
||||
|
||||
.. note::
|
||||
|
||||
There is a limitation on the compatibility of Criteria comparisons.
|
||||
You have to use scalar values only as the value in a comparison or
|
||||
the behaviour between different backends is not the same.
|
||||
Depending on whether the collection has already been loaded from the
|
||||
database or not, criteria matching may happen at the database/SQL level
|
||||
or on objects in memory. This may lead to different results and come
|
||||
surprising, for example when a code change in one place leads to a collection
|
||||
becoming initialized and, as a side effect, returning a different result
|
||||
or even breaking a ``matching()`` call somewhere else. Also, collection
|
||||
initialization state in practical use cases may differ from the one covered
|
||||
in unit tests.
|
||||
|
||||
Database level comparisons are based on scalar representations of the values
|
||||
stored in entity properties. The field names passed to expressions correspond
|
||||
to property names. Comparison and sorting may be affected by
|
||||
database-specific behavior. For example, MySQL enum types sort by index position,
|
||||
not lexicographically by value.
|
||||
|
||||
In-memory handling is based on the ``Selectable`` API of `Doctrine Collections <https://www.doctrine-project.org/projects/doctrine-collections/en/stable/index.html#matching>`.
|
||||
In this case, field names passed to expressions are being used to derive accessor
|
||||
method names. Strict type comparisons are used for equal and not-equal checks,
|
||||
and generally PHP language rules are being used for other comparison operators
|
||||
or sorting.
|
||||
|
||||
As a general guidance, for consistent results use the Criteria API with scalar
|
||||
values only. Note that ``DateTime`` and ``DateTimeImmutable`` are two predominant
|
||||
examples of value objects that are *not* scalars.
|
||||
|
||||
Refrain from using special database-level column types or custom Doctrine Types
|
||||
that may lead to database-specific comparison or sorting rules being applied, or
|
||||
to database-level values being different from object field values.
|
||||
|
||||
Provide accessor methods for all entity fields used in criteria expressions,
|
||||
and implement those methods in a way that their return value is the
|
||||
same as the database-level value.
|
||||
|
||||
@@ -166,7 +166,7 @@ your code. See the following code:
|
||||
|
||||
Traversing the object graph for parts that are lazy-loaded will
|
||||
easily trigger lots of SQL queries and will perform badly if used
|
||||
to heavily. Make sure to use DQL to fetch-join all the parts of the
|
||||
too heavily. Make sure to use DQL to fetch-join all the parts of the
|
||||
object-graph that you need as efficiently as possible.
|
||||
|
||||
|
||||
@@ -338,10 +338,11 @@ 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
|
||||
``EntityManager#remove()``. If the association is a collection, Doctrine will loop over all its elements and pass them to``EntityManager#remove()``.
|
||||
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM will
|
||||
fetch this association. If it's a Single association it will pass
|
||||
this entity to ``EntityManager#remove()``. If the association is a
|
||||
collection, Doctrine will loop over all its elements and pass them to
|
||||
``EntityManager#remove()``.
|
||||
In both cases the cascade remove semantics are applied recursively.
|
||||
For large object graphs this removal strategy can be very costly.
|
||||
2. Using a DQL ``DELETE`` statement allows you to delete multiple
|
||||
|
||||
@@ -18,7 +18,7 @@ setup for the latest code in trunk.
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
@@ -46,7 +46,7 @@ In order to work, this requires certain conventions:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$driver->setFileExtension('.xml');
|
||||
$driver->getLocator()->setFileExtension('.xml');
|
||||
|
||||
It is recommended to put all XML mapping documents in a single
|
||||
folder but you can spread the documents over several folders if you
|
||||
@@ -104,7 +104,7 @@ of several common elements:
|
||||
// Doctrine.Tests.ORM.Mapping.User.dcm.xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
@@ -770,7 +770,7 @@ entity relationship. You can define this in XML with the "association-key" attri
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
|
||||
@@ -1,80 +1,76 @@
|
||||
.. toc::
|
||||
:orphan:
|
||||
|
||||
.. tocheader:: Tutorials
|
||||
.. toctree::
|
||||
:caption: Tutorials
|
||||
:depth: 3
|
||||
|
||||
.. toctree::
|
||||
:depth: 3
|
||||
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
|
||||
tutorials/embeddables
|
||||
|
||||
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
|
||||
tutorials/embeddables
|
||||
.. toctree::
|
||||
:caption: Reference
|
||||
:depth: 3
|
||||
|
||||
.. toc::
|
||||
reference/architecture
|
||||
reference/configuration
|
||||
reference/faq
|
||||
reference/basic-mapping
|
||||
reference/association-mapping
|
||||
reference/inheritance-mapping
|
||||
reference/working-with-objects
|
||||
reference/working-with-associations
|
||||
reference/typedfieldmapper
|
||||
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-hydration
|
||||
reference/partial-objects
|
||||
reference/attributes-reference
|
||||
reference/xml-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
|
||||
|
||||
.. tocheader:: Reference
|
||||
.. toctree::
|
||||
:caption: Cookbook
|
||||
:depth: 3
|
||||
|
||||
.. toctree::
|
||||
:depth: 3
|
||||
|
||||
reference/architecture
|
||||
reference/configuration
|
||||
reference/faq
|
||||
reference/basic-mapping
|
||||
reference/association-mapping
|
||||
reference/inheritance-mapping
|
||||
reference/working-with-objects
|
||||
reference/working-with-associations
|
||||
reference/typedfieldmapper
|
||||
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/attributes-reference
|
||||
reference/xml-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
|
||||
|
||||
.. toc::
|
||||
|
||||
.. tocheader:: Cookbook
|
||||
|
||||
.. toctree::
|
||||
:depth: 3
|
||||
|
||||
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/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
|
||||
cookbook/aggregate-fields
|
||||
cookbook/custom-mapping-types
|
||||
cookbook/decorator-pattern
|
||||
cookbook/dql-custom-walkers
|
||||
cookbook/dql-user-defined-functions
|
||||
cookbook/generated-columns
|
||||
cookbook/implementing-arrayaccess-for-domain-objects
|
||||
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
|
||||
|
||||
@@ -54,7 +54,7 @@ and year of production as primary keys:
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
@@ -85,11 +85,12 @@ And for querying you can use arrays to both DQL and EntityRepositories:
|
||||
namespace VehicleCatalogue\Model;
|
||||
|
||||
// $em is the EntityManager
|
||||
$audi = $em->find("VehicleCatalogue\Model\Car", array("name" => "Audi A8", "year" => 2010));
|
||||
$audi = $em->find("VehicleCatalogue\Model\Car", ["name" => "Audi A8", "year" => 2010]);
|
||||
|
||||
$dql = "SELECT c FROM VehicleCatalogue\Model\Car c WHERE c.id = ?1";
|
||||
$dql = "SELECT c FROM VehicleCatalogue\Model\Car c WHERE c.name = ?1 AND c.year = ?2";
|
||||
$audi = $em->createQuery($dql)
|
||||
->setParameter(1, ["name" => "Audi A8", "year" => 2010])
|
||||
->setParameter(1, "Audi A8")
|
||||
->setParameter(2, 2010)
|
||||
->getSingleResult();
|
||||
|
||||
You can also use this entity in associations. Doctrine will then generate two foreign keys one for ``name``
|
||||
@@ -145,7 +146,7 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
#[OneToMany(targetEntity: ArticleAttribute::class, mappedBy: 'article', cascade: ['ALL'], indexBy: 'attribute')]
|
||||
private Collection $attributes;
|
||||
|
||||
public function addAttribute(string $name, ArticleAttribute $value): void
|
||||
public function addAttribute(string $name, string $value): void
|
||||
{
|
||||
$this->attributes[$name] = new ArticleAttribute($name, $value, $this);
|
||||
}
|
||||
@@ -174,7 +175,7 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
@@ -249,7 +250,7 @@ of products purchased and maybe even the current price.
|
||||
|
||||
public function __construct(
|
||||
#[ManyToOne(targetEntity: Customer::class)]
|
||||
private Customer $customer,
|
||||
private Customer $customer
|
||||
) {
|
||||
$this->items = new ArrayCollection();
|
||||
$this->created = new DateTime("now");
|
||||
@@ -294,6 +295,7 @@ of products purchased and maybe even the current price.
|
||||
$this->order = $order;
|
||||
$this->product = $product;
|
||||
$this->offeredPrice = $product->getCurrentPrice();
|
||||
$this->amount = $amount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ can be called without triggering a full load of the collection:
|
||||
- ``Collection#contains($entity)``
|
||||
- ``Collection#containsKey($key)``
|
||||
- ``Collection#count()``
|
||||
- ``Collection#first()``
|
||||
- ``Collection#get($key)``
|
||||
- ``Collection#isEmpty()``
|
||||
- ``Collection#slice($offset, $length = null)``
|
||||
|
||||
For each of the above methods the following semantics apply:
|
||||
@@ -69,7 +71,7 @@ switch to extra lazy as shown in these examples:
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
|
||||
@@ -139,12 +139,12 @@ step:
|
||||
|
||||
// Create a simple "default" Doctrine ORM configuration for Attributes
|
||||
$config = ORMSetup::createAttributeMetadataConfiguration(
|
||||
paths: array(__DIR__."/src"),
|
||||
paths: [__DIR__ . '/src'],
|
||||
isDevMode: true,
|
||||
);
|
||||
// or if you prefer XML
|
||||
// $config = ORMSetup::createXMLMetadataConfiguration(
|
||||
// paths: array(__DIR__."/config/xml"),
|
||||
// paths: [__DIR__ . '/config/xml'],
|
||||
// isDevMode: true,
|
||||
//);
|
||||
|
||||
@@ -514,7 +514,7 @@ methods, but you only need to choose one.
|
||||
|
||||
<!-- config/xml/Product.dcm.xml -->
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
@@ -1023,7 +1023,7 @@ the ``Product`` before:
|
||||
|
||||
<!-- config/xml/Bug.dcm.xml -->
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
@@ -1103,7 +1103,7 @@ Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
|
||||
<!-- config/xml/User.dcm.xml -->
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
@@ -1586,7 +1586,7 @@ we have to adjust the metadata slightly.
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ i.e. attributes and associations metadata in particular. The example here shows
|
||||
the overriding of a class that uses a trait but is similar when extending a base
|
||||
class as shown at the end of this tutorial.
|
||||
|
||||
Suppose we have a class ExampleEntityWithOverride. This class uses trait ExampleTrait:
|
||||
Suppose we have a class ``ExampleEntityWithOverride``. This class uses trait ``ExampleTrait``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -17,22 +17,20 @@ Suppose we have a class ExampleEntityWithOverride. This class uses trait Example
|
||||
|
||||
#[Entity]
|
||||
#[AttributeOverrides([
|
||||
new AttributeOverride('foo', [
|
||||
'column' => new Column([
|
||||
'name' => 'foo_overridden',
|
||||
'type' => 'integer',
|
||||
'length' => 140,
|
||||
'nullable' => false,
|
||||
'unique' => false,
|
||||
]),
|
||||
]),
|
||||
new AttributeOverride('foo', new Column(
|
||||
name: 'foo_overridden',
|
||||
type: 'integer',
|
||||
length: 140,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
)),
|
||||
])]
|
||||
#[AssociationOverrides([
|
||||
new AssociationOverride('bar', [
|
||||
'joinColumns' => new JoinColumn([
|
||||
'name' => 'example_entity_overridden_bar_id',
|
||||
'referencedColumnName' => 'id',
|
||||
]),
|
||||
new JoinColumn(
|
||||
name: 'example_entity_overridden_bar_id',
|
||||
referencedColumnName: 'id',
|
||||
),
|
||||
]),
|
||||
])]
|
||||
class ExampleEntityWithOverride
|
||||
@@ -47,7 +45,7 @@ Suppose we have a class ExampleEntityWithOverride. This class uses trait Example
|
||||
private $id;
|
||||
}
|
||||
|
||||
The docblock is showing metadata override of the attribute and association type. It
|
||||
``#[AttributeOverrides]`` contains metadata override of the attribute and association type. It
|
||||
basically changes the names of the columns mapped for a property ``foo`` and for
|
||||
the association ``bar`` which relates to Bar class shown above. Here is the trait
|
||||
which has mapping metadata that is overridden by the attribute above:
|
||||
|
||||
@@ -29,83 +29,11 @@ You can map indexed associations by adding:
|
||||
The code and mappings for the Market entity looks like this:
|
||||
|
||||
.. configuration-block::
|
||||
.. code-block:: attribute
|
||||
.. literalinclude:: working-with-indexed-associations/Market.php
|
||||
:language: attribute
|
||||
|
||||
<?php
|
||||
namespace Doctrine\Tests\Models\StockExchange;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
#[Entity]
|
||||
#[Table(name: 'exchange_markets')]
|
||||
class Market
|
||||
{
|
||||
#[Id, Column(type: 'integer'), GeneratedValue]
|
||||
private int|null $id = null;
|
||||
|
||||
#[Column(type: 'string')]
|
||||
private string $name;
|
||||
|
||||
/** @var Collection<string, Stock> */
|
||||
#[OneToMany(targetEntity: Stock::class, mappedBy: 'market', indexBy: 'symbol')]
|
||||
private Collection $stocks;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->stocks = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): int|null
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function addStock(Stock $stock): void
|
||||
{
|
||||
$this->stocks[$stock->getSymbol()] = $stock;
|
||||
}
|
||||
|
||||
public function getStock(string $symbol): Stock
|
||||
{
|
||||
if (!isset($this->stocks[$symbol])) {
|
||||
throw new \InvalidArgumentException("Symbol is not traded on this market.");
|
||||
}
|
||||
|
||||
return $this->stocks[$symbol];
|
||||
}
|
||||
|
||||
/** @return array<string, Stock> */
|
||||
public function getStocks(): array
|
||||
{
|
||||
return $this->stocks->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="Doctrine\Tests\Models\StockExchange\Market">
|
||||
<id name="id" type="integer">
|
||||
<generator strategy="AUTO" />
|
||||
</id>
|
||||
|
||||
<field name="name" type="string"/>
|
||||
|
||||
<one-to-many target-entity="Stock" mapped-by="market" field="stocks" index-by="symbol" />
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. literalinclude:: working-with-indexed-associations/market.xml
|
||||
:language: xml
|
||||
|
||||
Inside the ``addStock()`` method you can see how we directly set the key of the association to the symbol,
|
||||
so that we can work with the indexed association directly after invoking ``addStock()``. Inside ``getStock($symbol)``
|
||||
@@ -150,7 +78,7 @@ here are the code and mappings for it:
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://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">
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\StockExchange;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\GeneratedValue;
|
||||
use Doctrine\ORM\Mapping\Id;
|
||||
use Doctrine\ORM\Mapping\OneToMany;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
use InvalidArgumentException;
|
||||
|
||||
#[Entity]
|
||||
#[Table(name: 'exchange_markets')]
|
||||
class Market
|
||||
{
|
||||
#[Id]
|
||||
#[Column(type: 'integer')]
|
||||
#[GeneratedValue]
|
||||
private int|null $id = null;
|
||||
|
||||
#[Column(type: 'string')]
|
||||
private string $name;
|
||||
|
||||
/** @var Collection<string, Stock> */
|
||||
#[OneToMany(targetEntity: Stock::class, mappedBy: 'market', indexBy: 'symbol')]
|
||||
private Collection $stocks;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->stocks = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): int|null
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function addStock(Stock $stock): void
|
||||
{
|
||||
$this->stocks[$stock->getSymbol()] = $stock;
|
||||
}
|
||||
|
||||
public function getStock(string $symbol): Stock
|
||||
{
|
||||
if (! isset($this->stocks[$symbol])) {
|
||||
throw new InvalidArgumentException('Symbol is not traded on this market.');
|
||||
}
|
||||
|
||||
return $this->stocks[$symbol];
|
||||
}
|
||||
|
||||
/** @return array<string, Stock> */
|
||||
public function getStocks(): array
|
||||
{
|
||||
return $this->stocks->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://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="Doctrine\Tests\Models\StockExchange\Market">
|
||||
<id name="id" type="integer">
|
||||
<generator strategy="AUTO" />
|
||||
</id>
|
||||
|
||||
<field name="name" type="string"/>
|
||||
|
||||
<one-to-many target-entity="Stock" mapped-by="market" field="stocks" index-by="symbol" />
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
@@ -321,7 +321,7 @@
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="value" type="xs:NMTOKEN" use="required"/>
|
||||
<xs:attribute name="value" type="orm:type" use="required"/>
|
||||
<xs:attribute name="class" type="orm:fqcn" use="required"/>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
name="PHP_CodeSniffer"
|
||||
xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
|
||||
<arg name="basepath" value="."/>
|
||||
<arg name="extensions" value="php"/>
|
||||
<arg name="parallel" value="80"/>
|
||||
@@ -14,7 +16,6 @@
|
||||
<file>src</file>
|
||||
<file>tests</file>
|
||||
|
||||
<exclude-pattern>*/src/Mapping/InverseJoinColumn.php</exclude-pattern>
|
||||
<exclude-pattern>*/tests/Tests/Proxies/__CG__*</exclude-pattern>
|
||||
<exclude-pattern>*/tests/Tests/ORM/Tools/Export/export/*</exclude-pattern>
|
||||
|
||||
@@ -49,6 +50,8 @@
|
||||
</rule>
|
||||
|
||||
<rule ref="PSR1.Classes.ClassDeclaration.MultipleClasses">
|
||||
<exclude-pattern>src/Mapping/Driver/LoadMappingFileImplementation.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/GetReflectionClassImplementation.php</exclude-pattern>
|
||||
<exclude-pattern>tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@ includes:
|
||||
- phpstan-params.neon
|
||||
|
||||
parameters:
|
||||
reportUnmatchedIgnoredErrors: false # Some errors in the baseline only apply to DBAL 4
|
||||
ignoreErrors:
|
||||
# Symfony cache supports passing a key prefix to the clear method.
|
||||
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
|
||||
@@ -16,9 +17,22 @@ parameters:
|
||||
-
|
||||
message: '~^Method Doctrine\\ORM\\Query\\AST\\Functions\\TrimFunction::getTrimMode\(\) never returns .* so it can be removed from the return type\.$~'
|
||||
path: src/Query/AST/Functions/TrimFunction.php
|
||||
|
||||
-
|
||||
message: '~^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getArrayBindingType\(\) never returns .* so it can be removed from the return type\.$~'
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
message: '~.*getTrimExpression.*expects int.*~'
|
||||
path: src/Query/AST/Functions/TrimFunction.php
|
||||
|
||||
-
|
||||
message: '~^Call to static method unquoted\(\) on an unknown class Doctrine\\DBAL\\Schema\\Name\\Identifier\.$~'
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '~^Instantiated class Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName not found\.$~'
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '~^Call to an undefined method Doctrine\\DBAL\\Schema\\Table::addPrimaryKeyConstraint\(\)\.$~'
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
- '~^Class Doctrine\\DBAL\\Platforms\\SQLitePlatform not found\.$~'
|
||||
|
||||
@@ -27,3 +41,49 @@ parameters:
|
||||
message: '#Negated boolean expression is always false\.#'
|
||||
paths:
|
||||
- src/Mapping/Driver/AttributeDriver.php
|
||||
|
||||
-
|
||||
message: '~^Call to deprecated method getEventManager\(\) of class Doctrine\\DBAL\\Connection\.$~'
|
||||
path: src/EntityManager.php
|
||||
-
|
||||
message: '~deprecated class Doctrine\\DBAL\\Tools\\Console\\Command\\ReservedWordsCommand\:~'
|
||||
path: src/Tools/Console/ConsoleRunner.php
|
||||
|
||||
# Compatibility with Persistence 3
|
||||
-
|
||||
message: '#Expression on left side of \?\? is not nullable.#'
|
||||
path: src/Mapping/Driver/AttributeDriver.php
|
||||
|
||||
-
|
||||
message: '~^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getArrayBindingType\(\) never returns .* so it can be removed from the return type\.$~'
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '~getTypes.*should return~'
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '~.*appendLockHint.*expects.*LockMode given~'
|
||||
paths:
|
||||
- src/Persisters/Entity/BasicEntityPersister.php
|
||||
- src/Persisters/Entity/JoinedSubclassPersister.php
|
||||
|
||||
-
|
||||
message: '~.*executeStatement.*expects~'
|
||||
path: src/Query/Exec/MultiTableUpdateExecutor.php
|
||||
|
||||
-
|
||||
message: '~method_exists.*getEventManager~'
|
||||
path: src/EntityManager.php
|
||||
|
||||
-
|
||||
message: '~method_exists.*getIdentitySequence~'
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
-
|
||||
message: '~expand(Criteria)?Parameters.*should return array~'
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '~inferType.*never returns~'
|
||||
path: src/Query/ParameterTypeInferer.php
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
parameters:
|
||||
level: 5
|
||||
level: 7
|
||||
paths:
|
||||
- src
|
||||
- tests/StaticAnalysis
|
||||
@@ -8,4 +8,4 @@ parameters:
|
||||
earlyTerminatingMethodCalls:
|
||||
Doctrine\ORM\Query\Parser:
|
||||
- syntaxError
|
||||
phpVersion: 80200
|
||||
phpVersion: 80400
|
||||
|
||||
17
phpstan.neon
17
phpstan.neon
@@ -20,6 +20,18 @@ parameters:
|
||||
message: '~^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getArrayBindingType\(\) never returns .* so it can be removed from the return type\.$~'
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '~^Call to static method unquoted\(\) on an unknown class Doctrine\\DBAL\\Schema\\Name\\Identifier\.$~'
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '~^Instantiated class Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName not found\.$~'
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '~^Call to an undefined method Doctrine\\DBAL\\Schema\\Table::addPrimaryKeyConstraint\(\)\.$~'
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
# Compatibility with DBAL 3
|
||||
# See https://github.com/doctrine/dbal/pull/3480
|
||||
-
|
||||
@@ -45,3 +57,8 @@ parameters:
|
||||
message: '#Negated boolean expression is always false\.#'
|
||||
paths:
|
||||
- src/Mapping/Driver/AttributeDriver.php
|
||||
|
||||
# Compatibility with Persistence 3
|
||||
-
|
||||
message: '#Expression on left side of \?\? is not nullable.#'
|
||||
path: src/Mapping/Driver/AttributeDriver.php
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
@@ -67,5 +69,12 @@
|
||||
<var name="privileged_db_port" value="3306"/>
|
||||
-->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory>src</directory>
|
||||
</include>
|
||||
</source>
|
||||
</phpunit>
|
||||
|
||||
1238
psalm-baseline.xml
1238
psalm-baseline.xml
File diff suppressed because it is too large
Load Diff
245
psalm.xml
245
psalm.xml
@@ -1,245 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<psalm
|
||||
errorLevel="2"
|
||||
phpVersion="8.2"
|
||||
resolveFromConfigFile="true"
|
||||
findUnusedBaselineEntry="true"
|
||||
findUnusedCode="false"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="https://getpsalm.org/schema/config"
|
||||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
||||
errorBaseline="psalm-baseline.xml"
|
||||
>
|
||||
<projectFiles>
|
||||
<directory name="src" />
|
||||
<directory name="tests/StaticAnalysis" />
|
||||
<ignoreFiles>
|
||||
<directory name="vendor" />
|
||||
<file name="src/Mapping/Driver/AttributeReader.php" />
|
||||
</ignoreFiles>
|
||||
</projectFiles>
|
||||
<enableExtensions>
|
||||
<extension name="simplexml" />
|
||||
</enableExtensions>
|
||||
<issueHandlers>
|
||||
<DeprecatedClass>
|
||||
<errorLevel type="suppress">
|
||||
<!-- We wire the command as long as DBAL ships it -->
|
||||
<referencedClass name="Doctrine\DBAL\Tools\Console\Command\ReservedWordsCommand" />
|
||||
<!-- Remove on 3.0.x -->
|
||||
<referencedClass name="Doctrine\ORM\Event\LifecycleEventArgs"/>
|
||||
<referencedClass name="Doctrine\ORM\Exception\UnknownEntityNamespace"/>
|
||||
<referencedClass name="Doctrine\ORM\Mapping\Driver\AnnotationDriver"/>
|
||||
<referencedClass name="Doctrine\ORM\Mapping\Driver\YamlDriver"/>
|
||||
<referencedClass name="Doctrine\ORM\Mapping\NamedNativeQueries"/>
|
||||
<referencedClass name="Doctrine\ORM\Mapping\NamedNativeQuery"/>
|
||||
<referencedClass name="Doctrine\ORM\Mapping\NamedQueries"/>
|
||||
<referencedClass name="Doctrine\ORM\Mapping\NamedQuery"/>
|
||||
<referencedClass name="Doctrine\ORM\Query\AST\InExpression"/>
|
||||
<referencedClass name="Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand"/>
|
||||
<referencedClass name="Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand"/>
|
||||
<referencedClass name="Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand"/>
|
||||
<referencedClass name="Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand"/>
|
||||
<referencedClass name="Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand"/>
|
||||
<referencedClass name="Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper"/>
|
||||
<referencedClass name="Doctrine\ORM\Tools\Console\EntityManagerProvider\HelperSetManagerProvider"/>
|
||||
</errorLevel>
|
||||
</DeprecatedClass>
|
||||
<DeprecatedMethod>
|
||||
<errorLevel type="suppress">
|
||||
<!-- Remove on 3.0.x -->
|
||||
<!-- Compatibility with DBAL 3 -->
|
||||
<referencedMethod name="Doctrine\DBAL\Connection::getEventManager"/>
|
||||
<file name="src/Query/TreeWalkerChain.php"/>
|
||||
</errorLevel>
|
||||
</DeprecatedMethod>
|
||||
<DocblockTypeContradiction>
|
||||
<errorLevel type="suppress">
|
||||
<!-- We're catching invalid input here. -->
|
||||
<file name="src/Internal/Hydration/AbstractHydrator.php"/>
|
||||
|
||||
<!-- DBAL 3.2 forward compatibility -->
|
||||
<file name="src/Tools/Pagination/CountOutputWalker.php"/>
|
||||
<file name="src/Tools/Pagination/LimitSubqueryOutputWalker.php"/>
|
||||
<!-- https://github.com/vimeo/psalm/issues/8520 -->
|
||||
<file name="src/PersistentCollection.php"/>
|
||||
<!-- Remove on 4.0.x -->
|
||||
<file name="src/Mapping/Driver/AttributeDriver.php"/>
|
||||
<file name="src/Mapping/Driver/XmlDriver.php"/>
|
||||
<file name="src/ORMSetup.php"/>
|
||||
</errorLevel>
|
||||
</DocblockTypeContradiction>
|
||||
<ForbiddenCode>
|
||||
<errorLevel type="suppress">
|
||||
<file name="src/Tools/Debug.php"/>
|
||||
</errorLevel>
|
||||
</ForbiddenCode>
|
||||
<InvalidArgument>
|
||||
<errorLevel type="suppress">
|
||||
<referencedFunction name="Doctrine\ORM\Mapping\ClassMetadata::addInheritedAssociationMapping"/>
|
||||
</errorLevel>
|
||||
</InvalidArgument>
|
||||
<InvalidArrayAccess>
|
||||
<errorLevel type="suppress">
|
||||
<!-- https://github.com/vimeo/psalm/issues/9160 -->
|
||||
<file name="src/Mapping/ClassMetadataFactory.php"/>
|
||||
</errorLevel>
|
||||
</InvalidArrayAccess>
|
||||
<InvalidArrayAssignment>
|
||||
<errorLevel type="suppress">
|
||||
<!-- https://github.com/vimeo/psalm/issues/9160 -->
|
||||
<file name="src/Mapping/ClassMetadataFactory.php"/>
|
||||
</errorLevel>
|
||||
</InvalidArrayAssignment>
|
||||
<LessSpecificReturnStatement>
|
||||
<errorLevel type="suppress">
|
||||
<!-- In DBAL 4, column precision is nullable. See https://github.com/doctrine/dbal/pull/3511 -->
|
||||
<file name="src/Mapping/Driver/DatabaseDriver.php"/>
|
||||
</errorLevel>
|
||||
</LessSpecificReturnStatement>
|
||||
<MoreSpecificReturnType>
|
||||
<errorLevel type="suppress">
|
||||
<!-- In DBAL 4, the default column value is mixed. See https://github.com/doctrine/dbal/pull/3511 -->
|
||||
<file name="src/Mapping/Driver/DatabaseDriver.php"/>
|
||||
</errorLevel>
|
||||
</MoreSpecificReturnType>
|
||||
<InvalidReturnType>
|
||||
<errorLevel type="suppress">
|
||||
<!-- https://github.com/vimeo/psalm/issues/8819 -->
|
||||
<file name="src/Internal/Hydration/AbstractHydrator.php"/>
|
||||
</errorLevel>
|
||||
</InvalidReturnType>
|
||||
<InvalidParamDefault>
|
||||
<errorLevel type="suppress">
|
||||
<!-- Remove on 3.0.x -->
|
||||
<file name="src/Query/AST/InstanceOfExpression.php"/>
|
||||
</errorLevel>
|
||||
</InvalidParamDefault>
|
||||
<InvalidPropertyAssignmentValue>
|
||||
<errorLevel type="suppress">
|
||||
<!-- https://github.com/vimeo/psalm/issues/9155 -->
|
||||
<file name="src/Mapping/ClassMetadataFactory.php"/>
|
||||
</errorLevel>
|
||||
</InvalidPropertyAssignmentValue>
|
||||
<MethodSignatureMismatch>
|
||||
<errorLevel type="suppress">
|
||||
<!-- See https://github.com/vimeo/psalm/issues/7357 -->
|
||||
<file name="src/Mapping/ReflectionReadonlyProperty.php"/>
|
||||
</errorLevel>
|
||||
</MethodSignatureMismatch>
|
||||
<MissingParamType>
|
||||
<errorLevel type="suppress">
|
||||
<!-- Persistence 2 compatibility -->
|
||||
<file name="src/EntityManager.php"/>
|
||||
<file name="src/Mapping/ClassMetadataFactory.php"/>
|
||||
<file name="src/Mapping/ClassMetadata.php"/>
|
||||
</errorLevel>
|
||||
</MissingParamType>
|
||||
<PossiblyInvalidArgument>
|
||||
<errorLevel type="suppress">
|
||||
<!-- https://github.com/vimeo/psalm/issues/9155 -->
|
||||
<file name="src/Mapping/ClassMetadataFactory.php"/>
|
||||
</errorLevel>
|
||||
</PossiblyInvalidArgument>
|
||||
<PossiblyNullArrayOffset>
|
||||
<errorLevel type="suppress">
|
||||
<!-- https://github.com/vimeo/psalm/issues/7878 -->
|
||||
<file name="src/Persisters/Collection/ManyToManyPersister.php"/>
|
||||
</errorLevel>
|
||||
</PossiblyNullArrayOffset>
|
||||
<PropertyNotSetInConstructor>
|
||||
<errorLevel type="suppress">
|
||||
<directory name="src/Query/AST" />
|
||||
</errorLevel>
|
||||
</PropertyNotSetInConstructor>
|
||||
<PropertyTypeCoercion>
|
||||
<errorLevel type="suppress">
|
||||
<file name="src/Mapping/ClassMetadata.php"/>
|
||||
</errorLevel>
|
||||
</PropertyTypeCoercion>
|
||||
<RedundantCastGivenDocblockType>
|
||||
<errorLevel type="suppress">
|
||||
<!-- Can be removed once the "getMaxResults" methods of those classes have native parameter types -->
|
||||
<file name="src/Query.php"/>
|
||||
<file name="src/QueryBuilder.php"/>
|
||||
</errorLevel>
|
||||
</RedundantCastGivenDocblockType>
|
||||
<ReferenceConstraintViolation>
|
||||
<errorLevel type="suppress">
|
||||
<!-- https://github.com/vimeo/psalm/issues/9155 -->
|
||||
<file name="src/Mapping/ClassMetadataFactory.php"/>
|
||||
</errorLevel>
|
||||
</ReferenceConstraintViolation>
|
||||
<RiskyTruthyFalsyComparison>
|
||||
<!-- TODO: Enable this new rule on higher branches. -->
|
||||
<errorLevel type="suppress">
|
||||
<directory name="src" />
|
||||
</errorLevel>
|
||||
</RiskyTruthyFalsyComparison>
|
||||
<TooManyArguments>
|
||||
<errorLevel type="suppress">
|
||||
<!-- Symfony cache supports passing a key prefix to the clear method. -->
|
||||
<referencedFunction name="Psr\Cache\CacheItemPoolInterface::clear"/>
|
||||
|
||||
<!-- Persistence 2 compatibility -->
|
||||
<referencedFunction name="Doctrine\Persistence\ObjectManager::clear"/>
|
||||
|
||||
<!-- See https://github.com/doctrine/orm/issues/8850 -->
|
||||
<referencedFunction name="Doctrine\DBAL\Connection::lastInsertId"/>
|
||||
|
||||
<!-- FIXME -->
|
||||
<referencedFunction name="Doctrine\DBAL\DriverManager::getConnection"/>
|
||||
</errorLevel>
|
||||
</TooManyArguments>
|
||||
<TypeDoesNotContainNull>
|
||||
<errorLevel type="suppress">
|
||||
<!-- DBAL 3 compatibility -->
|
||||
<file name="src/Tools/SchemaTool.php"/>
|
||||
</errorLevel>
|
||||
</TypeDoesNotContainNull>
|
||||
<TypeDoesNotContainType>
|
||||
<errorLevel type="suppress">
|
||||
<file name="src/Internal/SQLResultCasing.php"/>
|
||||
<file name="src/Mapping/ClassMetadataFactory.php"/>
|
||||
<!-- DBAL 3 compatibility -->
|
||||
<file name="src/UnitOfWork.php"/>
|
||||
<file name="src/Utility/LockSqlHelper.php"/>
|
||||
</errorLevel>
|
||||
</TypeDoesNotContainType>
|
||||
<UndefinedClass>
|
||||
<errorLevel type="suppress">
|
||||
<!-- Compatibility with DBAL 3 -->
|
||||
<referencedClass name="Doctrine\DBAL\Platforms\SQLitePlatform"/>
|
||||
</errorLevel>
|
||||
</UndefinedClass>
|
||||
<UndefinedMethod>
|
||||
<errorLevel type="suppress">
|
||||
<!-- Compatibility with DBAL 3 -->
|
||||
<referencedMethod name="Doctrine\DBAL\Connection::getEventManager"/>
|
||||
<!-- FIXME -->
|
||||
<referencedMethod name="Doctrine\DBAL\Schema\SchemaDiff::toSaveSql"/>
|
||||
</errorLevel>
|
||||
</UndefinedMethod>
|
||||
<UndefinedPropertyFetch>
|
||||
<errorLevel type="suppress">
|
||||
<!-- https://github.com/vimeo/psalm/issues/7878 -->
|
||||
<file name="src/Persisters/Collection/ManyToManyPersister.php"/>
|
||||
<file name="src/PersistentCollection.php"/>
|
||||
<file name="src/Utility/PersisterHelper.php"/>
|
||||
<file name="src/Tools/SchemaValidator.php"/>
|
||||
</errorLevel>
|
||||
</UndefinedPropertyFetch>
|
||||
<UnhandledMatchCondition>
|
||||
<errorLevel type="suppress">
|
||||
<!-- We can be certain that those values are not matched. -->
|
||||
<file name="src/Persisters/Entity/BasicEntityPersister.php"/>
|
||||
</errorLevel>
|
||||
</UnhandledMatchCondition>
|
||||
<ArgumentTypeCoercion>
|
||||
<errorLevel type="suppress">
|
||||
<!-- See https://github.com/JetBrains/phpstorm-stubs/pull/1383 -->
|
||||
<file name="src/Mapping/ClassMetadata.php"/>
|
||||
</errorLevel>
|
||||
</ArgumentTypeCoercion>
|
||||
</issueHandlers>
|
||||
</psalm>
|
||||
@@ -83,7 +83,7 @@ abstract class AbstractQuery
|
||||
* The parameter map of this query.
|
||||
*
|
||||
* @var ArrayCollection|Parameter[]
|
||||
* @psalm-var ArrayCollection<int, Parameter>
|
||||
* @phpstan-var ArrayCollection<int, Parameter>
|
||||
*/
|
||||
protected ArrayCollection $parameters;
|
||||
|
||||
@@ -95,14 +95,14 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* The map of query hints.
|
||||
*
|
||||
* @psalm-var array<string, mixed>
|
||||
* @phpstan-var array<string, mixed>
|
||||
*/
|
||||
protected array $hints = [];
|
||||
|
||||
/**
|
||||
* The hydration mode.
|
||||
*
|
||||
* @psalm-var string|AbstractQuery::HYDRATE_*
|
||||
* @phpstan-var string|AbstractQuery::HYDRATE_*
|
||||
*/
|
||||
protected string|int $hydrationMode = self::HYDRATE_OBJECT;
|
||||
|
||||
@@ -130,7 +130,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Second level query cache mode.
|
||||
*
|
||||
* @psalm-var Cache::MODE_*|null
|
||||
* @phpstan-var Cache::MODE_*|null
|
||||
*/
|
||||
protected int|null $cacheMode = null;
|
||||
|
||||
@@ -217,14 +217,14 @@ abstract class AbstractQuery
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @psalm-return Cache::MODE_*|null */
|
||||
/** @phpstan-return Cache::MODE_*|null */
|
||||
public function getCacheMode(): int|null
|
||||
{
|
||||
return $this->cacheMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param Cache::MODE_* $cacheMode
|
||||
* @phpstan-param Cache::MODE_* $cacheMode
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
@@ -267,7 +267,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Get all defined parameters.
|
||||
*
|
||||
* @psalm-return ArrayCollection<int, Parameter>
|
||||
* @phpstan-return ArrayCollection<int, Parameter>
|
||||
*/
|
||||
public function getParameters(): ArrayCollection
|
||||
{
|
||||
@@ -286,7 +286,7 @@ abstract class AbstractQuery
|
||||
$key = Parameter::normalizeName($key);
|
||||
|
||||
$filteredParameters = $this->parameters->filter(
|
||||
static fn (Parameter $parameter): bool => $parameter->getName() === $key
|
||||
static fn (Parameter $parameter): bool => $parameter->getName() === $key,
|
||||
);
|
||||
|
||||
return ! $filteredParameters->isEmpty() ? $filteredParameters->first() : null;
|
||||
@@ -296,14 +296,14 @@ abstract class AbstractQuery
|
||||
* Sets a collection of query parameters.
|
||||
*
|
||||
* @param ArrayCollection|mixed[] $parameters
|
||||
* @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters
|
||||
* @phpstan-param ArrayCollection<int, Parameter>|mixed[] $parameters
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setParameters(ArrayCollection|array $parameters): static
|
||||
{
|
||||
if (is_array($parameters)) {
|
||||
/** @psalm-var ArrayCollection<int, Parameter> $parameterCollection */
|
||||
/** @phpstan-var ArrayCollection<int, Parameter> $parameterCollection */
|
||||
$parameterCollection = new ArrayCollection();
|
||||
|
||||
foreach ($parameters as $key => $value) {
|
||||
@@ -642,7 +642,7 @@ abstract class AbstractQuery
|
||||
* Change the default fetch mode of an association for this query.
|
||||
*
|
||||
* @param class-string $class
|
||||
* @psalm-param Mapping\ClassMetadata::FETCH_EAGER|Mapping\ClassMetadata::FETCH_LAZY $fetchMode
|
||||
* @phpstan-param Mapping\ClassMetadata::FETCH_EAGER|Mapping\ClassMetadata::FETCH_LAZY $fetchMode
|
||||
*/
|
||||
public function setFetchMode(string $class, string $assocName, int $fetchMode): static
|
||||
{
|
||||
@@ -656,7 +656,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @param string|int $hydrationMode Doctrine processing mode to be used during hydration process.
|
||||
* One of the Query::HYDRATE_* constants.
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode
|
||||
* @phpstan-param string|AbstractQuery::HYDRATE_* $hydrationMode
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
@@ -670,7 +670,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Gets the hydration mode currently used by the query.
|
||||
*
|
||||
* @psalm-return string|AbstractQuery::HYDRATE_*
|
||||
* @phpstan-return string|AbstractQuery::HYDRATE_*
|
||||
*/
|
||||
public function getHydrationMode(): string|int
|
||||
{
|
||||
@@ -682,7 +682,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* Alias for execute(null, $hydrationMode = HYDRATE_OBJECT).
|
||||
*
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode
|
||||
* @phpstan-param string|AbstractQuery::HYDRATE_* $hydrationMode
|
||||
*/
|
||||
public function getResult(string|int $hydrationMode = self::HYDRATE_OBJECT): mixed
|
||||
{
|
||||
@@ -728,7 +728,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Get exactly one result or null.
|
||||
*
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
* @phpstan-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*
|
||||
* @throws NonUniqueResultException
|
||||
*/
|
||||
@@ -763,7 +763,7 @@ abstract class AbstractQuery
|
||||
* If the result is not unique, a NonUniqueResultException is thrown.
|
||||
* If there is no result, a NoResultException is thrown.
|
||||
*
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
* @phpstan-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*
|
||||
* @throws NonUniqueResultException If the query result is not unique.
|
||||
* @throws NoResultException If the query returned no result.
|
||||
@@ -843,8 +843,8 @@ abstract class AbstractQuery
|
||||
* Executes the query and returns an iterable that can be used to incrementally
|
||||
* iterate over the result.
|
||||
*
|
||||
* @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
* @phpstan-param ArrayCollection<int, Parameter>|mixed[] $parameters
|
||||
* @phpstan-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*
|
||||
* @return iterable<mixed>
|
||||
*/
|
||||
@@ -877,8 +877,8 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Executes the query.
|
||||
*
|
||||
* @psalm-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
* @phpstan-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
|
||||
* @phpstan-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*/
|
||||
public function execute(
|
||||
ArrayCollection|array|null $parameters = null,
|
||||
@@ -894,8 +894,8 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Execute query ignoring second level cache.
|
||||
*
|
||||
* @psalm-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
* @phpstan-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
|
||||
* @phpstan-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*/
|
||||
private function executeIgnoreQueryCache(
|
||||
ArrayCollection|array|null $parameters = null,
|
||||
@@ -965,8 +965,8 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Load from second level cache or executes the query and put into cache.
|
||||
*
|
||||
* @psalm-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
* @phpstan-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
|
||||
* @phpstan-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*/
|
||||
private function executeUsingQueryCache(
|
||||
ArrayCollection|array|null $parameters = null,
|
||||
@@ -1029,7 +1029,7 @@ abstract class AbstractQuery
|
||||
* automatically generated for you.
|
||||
*
|
||||
* @return string[] ($key, $hash)
|
||||
* @psalm-return array{string, string} ($key, $hash)
|
||||
* @phpstan-return array{string, string} ($key, $hash)
|
||||
*/
|
||||
protected function getHydrationCacheId(): array
|
||||
{
|
||||
|
||||
@@ -22,18 +22,21 @@ class CollectionCacheKey extends CacheKey
|
||||
public readonly array $ownerIdentifier;
|
||||
|
||||
/**
|
||||
* @param class-string $entityClass The owner entity class.
|
||||
* @param array<string, mixed> $ownerIdentifier The identifier of the owning entity.
|
||||
* @param class-string $entityClass The owner entity class
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $entityClass,
|
||||
public readonly string $association,
|
||||
array $ownerIdentifier,
|
||||
string $filterHash = '',
|
||||
) {
|
||||
ksort($ownerIdentifier);
|
||||
|
||||
$this->ownerIdentifier = $ownerIdentifier;
|
||||
|
||||
parent::__construct(str_replace('\\', '.', strtolower($entityClass)) . '_' . implode(' ', $ownerIdentifier) . '__' . $association);
|
||||
$filterHash = $filterHash === '' ? '' : '_' . $filterHash;
|
||||
|
||||
parent::__construct(str_replace('\\', '.', strtolower($entityClass)) . '_' . implode(' ', $ownerIdentifier) . '__' . $association . $filterHash);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class DefaultCache implements Cache
|
||||
|
||||
/**
|
||||
* @var QueryCache[]
|
||||
* @psalm-var array<string, QueryCache>
|
||||
* @phpstan-var array<string, QueryCache>
|
||||
*/
|
||||
private array $queryCaches = [];
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function array_map;
|
||||
@@ -210,6 +211,10 @@ class DefaultQueryCache implements QueryCache
|
||||
throw FeatureNotImplemented::nonSelectStatements();
|
||||
}
|
||||
|
||||
if (($hints[SqlWalker::HINT_PARTIAL] ?? false) === true || ($hints[Query::HINT_FORCE_PARTIAL_LOAD] ?? false) === true) {
|
||||
throw FeatureNotImplemented::partialEntities();
|
||||
}
|
||||
|
||||
if (! ($key->cacheMode & Cache::MODE_PUT)) {
|
||||
return false;
|
||||
}
|
||||
@@ -226,7 +231,6 @@ class DefaultQueryCache implements QueryCache
|
||||
$region = $persister->getCacheRegion();
|
||||
|
||||
$cm = $this->em->getClassMetadata($entityName);
|
||||
assert($cm instanceof ClassMetadata);
|
||||
|
||||
foreach ($result as $index => $entity) {
|
||||
$identifier = $this->uow->getEntityIdentifier($entity);
|
||||
@@ -292,7 +296,7 @@ class DefaultQueryCache implements QueryCache
|
||||
|
||||
/**
|
||||
* @return mixed[]|null
|
||||
* @psalm-return array{targetEntity: class-string, type: mixed, list?: array[], identifier?: array}|null
|
||||
* @phpstan-return array{targetEntity: class-string, type: mixed, list?: array[], identifier?: array}|null
|
||||
*/
|
||||
private function storeAssociationCache(QueryCacheKey $key, AssociationMapping $assoc, mixed $assocValue): array|null
|
||||
{
|
||||
@@ -343,7 +347,7 @@ class DefaultQueryCache implements QueryCache
|
||||
];
|
||||
}
|
||||
|
||||
/** @psalm-return list<mixed>|object|null */
|
||||
/** @phpstan-return list<mixed>|object|null */
|
||||
private function getAssociationValue(
|
||||
ResultSetMapping $rsm,
|
||||
string $assocAlias,
|
||||
@@ -369,9 +373,9 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param array<array-key, array{field: string, class: string}> $path
|
||||
* @phpstan-param array<array-key, array{field: string, class: string}> $path
|
||||
*
|
||||
* @psalm-return list<mixed>|object|null
|
||||
* @phpstan-return list<mixed>|object|null
|
||||
*/
|
||||
private function getAssociationPathValue(mixed $value, array $path): array|object|null
|
||||
{
|
||||
|
||||
@@ -11,8 +11,8 @@ use function array_map;
|
||||
class EntityCacheEntry implements CacheEntry
|
||||
{
|
||||
/**
|
||||
* @param array<string,mixed> $data The entity map data
|
||||
* @psalm-param class-string $class The entity class name
|
||||
* @param class-string $class The entity class name
|
||||
* @param array<string,mixed> $data The entity map data
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $class,
|
||||
|
||||
@@ -20,4 +20,9 @@ class FeatureNotImplemented extends CacheException
|
||||
{
|
||||
return new self('Second-level cache query supports only select statements.');
|
||||
}
|
||||
|
||||
public static function partialEntities(): self
|
||||
{
|
||||
return new self('Second level cache does not support partial entities.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Doctrine\ORM\Query\FilterCollection;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function array_values;
|
||||
@@ -35,6 +36,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
protected array $queuedCache = [];
|
||||
|
||||
protected string $regionName;
|
||||
protected FilterCollection $filters;
|
||||
protected CollectionHydrator $hydrator;
|
||||
protected CacheLogger|null $cacheLogger;
|
||||
|
||||
@@ -48,6 +50,10 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
$cacheConfig = $configuration->getSecondLevelCacheConfiguration();
|
||||
$cacheFactory = $cacheConfig->getCacheFactory();
|
||||
|
||||
$this->region = $region;
|
||||
$this->persister = $persister;
|
||||
$this->association = $association;
|
||||
$this->filters = $em->getFilters();
|
||||
$this->regionName = $region->getName();
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->metadataFactory = $em->getMetadataFactory();
|
||||
@@ -135,7 +141,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
public function count(PersistentCollection $collection): int
|
||||
{
|
||||
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
|
||||
$key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId);
|
||||
$key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId, $this->filters->getHash());
|
||||
$entry = $this->region->get($key);
|
||||
|
||||
if ($entry !== null) {
|
||||
|
||||
@@ -36,7 +36,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
public function delete(PersistentCollection $collection): void
|
||||
{
|
||||
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
|
||||
$key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId);
|
||||
$key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId, $this->filters->getHash());
|
||||
|
||||
$this->persister->delete($collection);
|
||||
|
||||
@@ -53,7 +53,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
}
|
||||
|
||||
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
|
||||
$key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId);
|
||||
$key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId, $this->filters->getHash());
|
||||
|
||||
// Invalidate non initialized collections OR ordered collection
|
||||
if ($isDirty && ! $isInitialized || $this->association->isOrdered()) {
|
||||
|
||||
@@ -61,7 +61,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
public function delete(PersistentCollection $collection): void
|
||||
{
|
||||
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
|
||||
$key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId);
|
||||
$key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId, $this->filters->getHash());
|
||||
$lock = $this->region->lock($key);
|
||||
|
||||
$this->persister->delete($collection);
|
||||
@@ -88,7 +88,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
$this->persister->update($collection);
|
||||
|
||||
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
|
||||
$key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId);
|
||||
$key = new CollectionCacheKey($this->sourceEntity->rootEntityName, $this->association->fieldName, $ownerId, $this->filters->getHash());
|
||||
$lock = $this->region->lock($key);
|
||||
|
||||
if ($lock === null) {
|
||||
|
||||
@@ -24,11 +24,12 @@ use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Doctrine\ORM\Query\FilterCollection;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function array_merge;
|
||||
use function assert;
|
||||
use function func_get_args;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
|
||||
@@ -44,6 +45,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
protected TimestampCacheKey $timestampKey;
|
||||
protected EntityHydrator $hydrator;
|
||||
protected Cache $cache;
|
||||
protected FilterCollection $filters;
|
||||
protected CacheLogger|null $cacheLogger = null;
|
||||
protected string $regionName;
|
||||
|
||||
@@ -65,6 +67,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
$cacheFactory = $cacheConfig->getCacheFactory();
|
||||
|
||||
$this->cache = $em->getCache();
|
||||
$this->filters = $em->getFilters();
|
||||
$this->regionName = $region->getName();
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->metadataFactory = $em->getMetadataFactory();
|
||||
@@ -216,7 +219,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
? $this->persister->expandCriteriaParameters($criteria)
|
||||
: $this->persister->expandParameters($criteria);
|
||||
|
||||
return sha1($query . serialize($params) . serialize($orderBy) . $limit . $offset);
|
||||
return sha1($query . serialize($params) . serialize($orderBy) . $limit . $offset . $this->filters->getHash());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -473,7 +476,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
|
||||
$key = $this->buildCollectionCacheKey($assoc, $ownerId);
|
||||
$key = $this->buildCollectionCacheKey($assoc, $ownerId, $this->filters->getHash());
|
||||
$list = $persister->loadCollectionCache($collection, $key);
|
||||
|
||||
if ($list !== null) {
|
||||
@@ -504,7 +507,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
|
||||
$key = $this->buildCollectionCacheKey($assoc, $ownerId);
|
||||
$key = $this->buildCollectionCacheKey($assoc, $ownerId, $this->filters->getHash());
|
||||
$list = $persister->loadCollectionCache($collection, $key);
|
||||
|
||||
if ($list !== null) {
|
||||
@@ -547,11 +550,15 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $ownerId */
|
||||
protected function buildCollectionCacheKey(AssociationMapping $association, array $ownerId): CollectionCacheKey
|
||||
protected function buildCollectionCacheKey(AssociationMapping $association, array $ownerId, /* string $filterHash */): CollectionCacheKey
|
||||
{
|
||||
$metadata = $this->metadataFactory->getMetadataFor($association->sourceEntity);
|
||||
assert($metadata instanceof ClassMetadata);
|
||||
$filterHash = (string) (func_get_args()[2] ?? ''); // todo: move to argument in next major release
|
||||
|
||||
return new CollectionCacheKey($metadata->rootEntityName, $association->fieldName, $ownerId);
|
||||
return new CollectionCacheKey(
|
||||
$this->metadataFactory->getMetadataFor($association->sourceEntity)->rootEntityName,
|
||||
$association->fieldName,
|
||||
$ownerId,
|
||||
$filterHash,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,16 +41,16 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/** @var mixed[] */
|
||||
protected array $attributes = [];
|
||||
|
||||
/** @psalm-var array<class-string<AbstractPlatform>, ClassMetadata::GENERATOR_TYPE_*> */
|
||||
/** @phpstan-var array<class-string<AbstractPlatform>, ClassMetadata::GENERATOR_TYPE_*> */
|
||||
private $identityGenerationPreferences = [];
|
||||
|
||||
/** @psalm-param array<class-string<AbstractPlatform>, ClassMetadata::GENERATOR_TYPE_*> $value */
|
||||
/** @phpstan-param array<class-string<AbstractPlatform>, ClassMetadata::GENERATOR_TYPE_*> $value */
|
||||
public function setIdentityGenerationPreferences(array $value): void
|
||||
{
|
||||
$this->identityGenerationPreferences = $value;
|
||||
}
|
||||
|
||||
/** @psalm-return array<class-string<AbstractPlatform>, ClassMetadata::GENERATOR_TYPE_*> $value */
|
||||
/** @phpstan-return array<class-string<AbstractPlatform>, ClassMetadata::GENERATOR_TYPE_*> $value */
|
||||
public function getIdentityGenerationPreferences(): array
|
||||
{
|
||||
return $this->identityGenerationPreferences;
|
||||
@@ -122,7 +122,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets the entity alias map.
|
||||
*
|
||||
* @psalm-param array<string, string> $entityNamespaces
|
||||
* @phpstan-param array<string, string> $entityNamespaces
|
||||
*/
|
||||
public function setEntityNamespaces(array $entityNamespaces): void
|
||||
{
|
||||
@@ -132,7 +132,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Retrieves the list of registered entity namespace aliases.
|
||||
*
|
||||
* @psalm-return array<string, string>
|
||||
* @phpstan-return array<string, string>
|
||||
*/
|
||||
public function getEntityNamespaces(): array
|
||||
{
|
||||
@@ -191,7 +191,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param class-string|callable $className Class name or a callable that returns the function.
|
||||
* @psalm-param class-string<FunctionNode>|callable(string):FunctionNode $className
|
||||
* @phpstan-param class-string<FunctionNode>|callable(string):FunctionNode $className
|
||||
*/
|
||||
public function addCustomStringFunction(string $name, string|callable $className): void
|
||||
{
|
||||
@@ -201,7 +201,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the implementation class name of a registered custom string DQL function.
|
||||
*
|
||||
* @psalm-return class-string<FunctionNode>|callable(string):FunctionNode|null
|
||||
* @phpstan-return class-string<FunctionNode>|callable(string):FunctionNode|null
|
||||
*/
|
||||
public function getCustomStringFunction(string $name): string|callable|null
|
||||
{
|
||||
@@ -218,7 +218,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* Any previously added string functions are discarded.
|
||||
*
|
||||
* @psalm-param array<string, class-string<FunctionNode>|callable(string):FunctionNode> $functions The map of custom
|
||||
* @phpstan-param array<string, class-string<FunctionNode>|callable(string):FunctionNode> $functions The map of custom
|
||||
* DQL string functions.
|
||||
*/
|
||||
public function setCustomStringFunctions(array $functions): void
|
||||
@@ -236,7 +236,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param class-string|callable $className Class name or a callable that returns the function.
|
||||
* @psalm-param class-string<FunctionNode>|callable(string):FunctionNode $className
|
||||
* @phpstan-param class-string<FunctionNode>|callable(string):FunctionNode $className
|
||||
*/
|
||||
public function addCustomNumericFunction(string $name, string|callable $className): void
|
||||
{
|
||||
@@ -246,7 +246,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the implementation class name of a registered custom numeric DQL function.
|
||||
*
|
||||
* @psalm-return ?class-string<FunctionNode>|callable(string):FunctionNode
|
||||
* @phpstan-return class-string<FunctionNode>|callable(string):FunctionNode|null
|
||||
*/
|
||||
public function getCustomNumericFunction(string $name): string|callable|null
|
||||
{
|
||||
@@ -263,8 +263,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* Any previously added numeric functions are discarded.
|
||||
*
|
||||
* @psalm-param array<string, class-string> $functions The map of custom
|
||||
* DQL numeric functions.
|
||||
* @param array<string, class-string> $functions The map of custom
|
||||
* DQL numeric functions.
|
||||
*/
|
||||
public function setCustomNumericFunctions(array $functions): void
|
||||
{
|
||||
@@ -281,7 +281,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param string|callable $className Class name or a callable that returns the function.
|
||||
* @psalm-param class-string<FunctionNode>|callable(string):FunctionNode $className
|
||||
* @phpstan-param class-string<FunctionNode>|callable(string):FunctionNode $className
|
||||
*/
|
||||
public function addCustomDatetimeFunction(string $name, string|callable $className): void
|
||||
{
|
||||
@@ -291,7 +291,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the implementation class name of a registered custom date/time DQL function.
|
||||
*
|
||||
* @psalm-return class-string|callable|null
|
||||
* @return class-string|callable|null
|
||||
*/
|
||||
public function getCustomDatetimeFunction(string $name): string|callable|null
|
||||
{
|
||||
@@ -309,7 +309,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* Any previously added date/time functions are discarded.
|
||||
*
|
||||
* @param array $functions The map of custom DQL date/time functions.
|
||||
* @psalm-param array<string, class-string<FunctionNode>|callable(string):FunctionNode> $functions
|
||||
* @phpstan-param array<string, class-string<FunctionNode>|callable(string):FunctionNode> $functions
|
||||
*/
|
||||
public function setCustomDatetimeFunctions(array $functions): void
|
||||
{
|
||||
@@ -351,7 +351,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the hydrator class for the given hydration mode name.
|
||||
*
|
||||
* @psalm-return class-string<AbstractHydrator>|null
|
||||
* @return class-string<AbstractHydrator>|null
|
||||
*/
|
||||
public function getCustomHydrationMode(string $modeName): string|null
|
||||
{
|
||||
@@ -361,7 +361,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Adds a custom hydration mode.
|
||||
*
|
||||
* @psalm-param class-string<AbstractHydrator> $hydrator
|
||||
* @param class-string<AbstractHydrator> $hydrator
|
||||
*/
|
||||
public function addCustomHydrationMode(string $modeName, string $hydrator): void
|
||||
{
|
||||
@@ -371,14 +371,14 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets a class metadata factory.
|
||||
*
|
||||
* @psalm-param class-string $cmfName
|
||||
* @param class-string $cmfName
|
||||
*/
|
||||
public function setClassMetadataFactoryName(string $cmfName): void
|
||||
{
|
||||
$this->attributes['classMetadataFactoryName'] = $cmfName;
|
||||
}
|
||||
|
||||
/** @psalm-return class-string */
|
||||
/** @return class-string */
|
||||
public function getClassMetadataFactoryName(): string
|
||||
{
|
||||
if (! isset($this->attributes['classMetadataFactoryName'])) {
|
||||
@@ -391,8 +391,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Adds a filter to the list of possible filters.
|
||||
*
|
||||
* @param string $className The class name of the filter.
|
||||
* @psalm-param class-string<SQLFilter> $className
|
||||
* @param class-string<SQLFilter> $className The class name of the filter.
|
||||
*/
|
||||
public function addFilter(string $name, string $className): void
|
||||
{
|
||||
@@ -402,9 +401,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the class name for a given filter name.
|
||||
*
|
||||
* @return string|null The class name of the filter, or null if it is not
|
||||
* defined.
|
||||
* @psalm-return class-string<SQLFilter>|null
|
||||
* @return class-string<SQLFilter>|null The class name of the filter,
|
||||
* or null if it is not defined.
|
||||
*/
|
||||
public function getFilterClassName(string $name): string|null
|
||||
{
|
||||
@@ -414,7 +412,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets default repository class.
|
||||
*
|
||||
* @psalm-param class-string<EntityRepository> $className
|
||||
* @param class-string<EntityRepository> $className
|
||||
*
|
||||
* @throws InvalidEntityRepository If $classname is not an ObjectRepository.
|
||||
*/
|
||||
@@ -430,7 +428,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Get default repository class.
|
||||
*
|
||||
* @psalm-return class-string<EntityRepository>
|
||||
* @return class-string<EntityRepository>
|
||||
*/
|
||||
public function getDefaultRepositoryClassName(): string
|
||||
{
|
||||
@@ -540,7 +538,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Returns query hints, which will be applied to every query in application
|
||||
*
|
||||
* @psalm-return array<string, mixed>
|
||||
* @phpstan-return array<string, mixed>
|
||||
*/
|
||||
public function getDefaultQueryHints(): array
|
||||
{
|
||||
@@ -550,7 +548,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets array of query hints, which will be applied to every query in application
|
||||
*
|
||||
* @psalm-param array<string, mixed> $defaultQueryHints
|
||||
* @phpstan-param array<string, mixed> $defaultQueryHints
|
||||
*/
|
||||
public function setDefaultQueryHints(array $defaultQueryHints): void
|
||||
{
|
||||
|
||||
@@ -24,7 +24,6 @@ use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\Query\FilterCollection;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Repository\RepositoryFactory;
|
||||
use Throwable;
|
||||
|
||||
use function array_keys;
|
||||
use function is_array;
|
||||
@@ -178,18 +177,24 @@ class EntityManager implements EntityManagerInterface
|
||||
{
|
||||
$this->conn->beginTransaction();
|
||||
|
||||
$successful = false;
|
||||
|
||||
try {
|
||||
$return = $func($this);
|
||||
|
||||
$this->flush();
|
||||
$this->conn->commit();
|
||||
|
||||
return $return;
|
||||
} catch (Throwable $e) {
|
||||
$this->close();
|
||||
$this->conn->rollBack();
|
||||
$successful = true;
|
||||
|
||||
throw $e;
|
||||
return $return;
|
||||
} finally {
|
||||
if (! $successful) {
|
||||
$this->close();
|
||||
if ($this->conn->isTransactionActive()) {
|
||||
$this->conn->rollBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,9 +484,9 @@ class EntityManager implements EntityManagerInterface
|
||||
/**
|
||||
* Gets the repository for an entity class.
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @param class-string<T> $className The name of the entity.
|
||||
*
|
||||
* @psalm-return EntityRepository<T>
|
||||
* @return EntityRepository<T> The repository class.
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
@@ -560,9 +565,9 @@ class EntityManager implements EntityManagerInterface
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isUninitializedObject($obj): bool
|
||||
public function isUninitializedObject($value): bool
|
||||
{
|
||||
return $this->unitOfWork->isUninitializedObject($obj);
|
||||
return $this->unitOfWork->isUninitializedObject($value);
|
||||
}
|
||||
|
||||
public function getFilters(): FilterCollection
|
||||
@@ -581,7 +586,7 @@ class EntityManager implements EntityManagerInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param LockMode::* $lockMode
|
||||
* @phpstan-param LockMode::* $lockMode
|
||||
*
|
||||
* @throws OptimisticLockException
|
||||
* @throws TransactionRequiredException
|
||||
|
||||
@@ -22,9 +22,9 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @param class-string<T> $className
|
||||
*
|
||||
* @psalm-return EntityRepository<T>
|
||||
* @return EntityRepository<T>
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
@@ -71,10 +71,10 @@ interface EntityManagerInterface extends ObjectManager
|
||||
* If an exception occurs during execution of the function or flushing or transaction commit,
|
||||
* the transaction is rolled back, the EntityManager closed and the exception re-thrown.
|
||||
*
|
||||
* @psalm-param callable(self): T $func The function to execute transactionally.
|
||||
* @phpstan-param callable(self): T $func The function to execute transactionally.
|
||||
*
|
||||
* @return mixed The value returned from the closure.
|
||||
* @psalm-return T
|
||||
* @phpstan-return T
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
@@ -117,11 +117,11 @@ interface EntityManagerInterface extends ObjectManager
|
||||
* during the search.
|
||||
* @param int|null $lockVersion The version of the entity to find when using
|
||||
* optimistic locking.
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param LockMode::*|null $lockMode
|
||||
* @phpstan-param class-string<T> $className
|
||||
* @phpstan-param LockMode::*|null $lockMode
|
||||
*
|
||||
* @return object|null The entity instance or NULL if the entity can not be found.
|
||||
* @psalm-return T|null
|
||||
* @phpstan-return T|null
|
||||
*
|
||||
* @throws OptimisticLockException
|
||||
* @throws ORMInvalidArgumentException
|
||||
@@ -139,7 +139,7 @@ interface EntityManagerInterface extends ObjectManager
|
||||
* @param LockMode|int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
|
||||
* or NULL if no specific lock mode should be used
|
||||
* during the search.
|
||||
* @psalm-param LockMode::*|null $lockMode
|
||||
* @phpstan-param LockMode::*|null $lockMode
|
||||
*
|
||||
* @throws ORMInvalidArgumentException
|
||||
* @throws ORMException
|
||||
@@ -151,11 +151,10 @@ interface EntityManagerInterface extends ObjectManager
|
||||
* Gets a reference to the entity identified by the given type and identifier
|
||||
* without actually loading it, if the entity is not yet loaded.
|
||||
*
|
||||
* @param string $entityName The name of the entity type.
|
||||
* @param mixed $id The entity identifier.
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @param class-string<T> $entityName The name of the entity type.
|
||||
* @param mixed $id The entity identifier.
|
||||
*
|
||||
* @psalm-return T|null
|
||||
* @return T|null The entity reference.
|
||||
*
|
||||
* @throws ORMException
|
||||
*
|
||||
@@ -173,7 +172,7 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* Acquire a lock on the given entity.
|
||||
*
|
||||
* @psalm-param LockMode::* $lockMode
|
||||
* @phpstan-param LockMode::* $lockMode
|
||||
*
|
||||
* @throws OptimisticLockException
|
||||
* @throws PessimisticLockException
|
||||
@@ -203,7 +202,7 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* Create a new instance for the given hydration mode.
|
||||
*
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode
|
||||
* @phpstan-param string|AbstractQuery::HYDRATE_* $hydrationMode
|
||||
*
|
||||
* @throws ORMException
|
||||
*/
|
||||
@@ -232,11 +231,11 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param string|class-string<T> $className
|
||||
* @param string|class-string<T> $className
|
||||
*
|
||||
* @psalm-return ($className is class-string<T> ? Mapping\ClassMetadata<T> : Mapping\ClassMetadata<object>)
|
||||
* @phpstan-return ($className is class-string<T> ? Mapping\ClassMetadata<T> : Mapping\ClassMetadata<object>)
|
||||
*
|
||||
* @psalm-template T of object
|
||||
* @phpstan-template T of object
|
||||
*/
|
||||
public function getClassMetadata(string $className): Mapping\ClassMetadata;
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ use function substr;
|
||||
*/
|
||||
class EntityRepository implements ObjectRepository, Selectable
|
||||
{
|
||||
/** @psalm-var class-string<T> */
|
||||
/** @var class-string<T> */
|
||||
private readonly string $entityName;
|
||||
private static Inflector|null $inflector = null;
|
||||
|
||||
/** @psalm-param ClassMetadata<T> $class */
|
||||
/** @param ClassMetadata<T> $class */
|
||||
public function __construct(
|
||||
private readonly EntityManagerInterface $em,
|
||||
private readonly ClassMetadata $class,
|
||||
@@ -76,10 +76,10 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* @param LockMode|int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
|
||||
* or NULL if no specific lock mode should be used
|
||||
* during the search.
|
||||
* @psalm-param LockMode::*|null $lockMode
|
||||
* @phpstan-param LockMode::*|null $lockMode
|
||||
*
|
||||
* @return object|null The entity instance or NULL if the entity can not be found.
|
||||
* @psalm-return ?T
|
||||
* @phpstan-return ?T
|
||||
*/
|
||||
public function find(mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null
|
||||
{
|
||||
@@ -89,7 +89,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
/**
|
||||
* Finds all entities in the repository.
|
||||
*
|
||||
* @psalm-return list<T> The entities.
|
||||
* @phpstan-return list<T> The entities.
|
||||
*/
|
||||
public function findAll(): array
|
||||
{
|
||||
@@ -101,7 +101,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-return list<T>
|
||||
* @phpstan-return list<T>
|
||||
*/
|
||||
public function findBy(array $criteria, array|null $orderBy = null, int|null $limit = null, int|null $offset = null): array
|
||||
{
|
||||
@@ -113,10 +113,10 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
/**
|
||||
* Finds a single entity by a set of criteria.
|
||||
*
|
||||
* @psalm-param array<string, mixed> $criteria
|
||||
* @psalm-param array<string, string>|null $orderBy
|
||||
* @phpstan-param array<string, mixed> $criteria
|
||||
* @phpstan-param array<string, string>|null $orderBy
|
||||
*
|
||||
* @psalm-return T|null
|
||||
* @phpstan-return T|null
|
||||
*/
|
||||
public function findOneBy(array $criteria, array|null $orderBy = null): object|null
|
||||
{
|
||||
@@ -128,9 +128,10 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
/**
|
||||
* Counts entities by a set of criteria.
|
||||
*
|
||||
* @psalm-param array<string, mixed> $criteria
|
||||
* @phpstan-param array<string, mixed> $criteria
|
||||
*
|
||||
* @return int The cardinality of the objects that match the given criteria.
|
||||
* @phpstan-return 0|positive-int
|
||||
*
|
||||
* @todo Add this method to `ObjectRepository` interface in the next major release
|
||||
*/
|
||||
@@ -143,7 +144,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* Adds support for magic method calls.
|
||||
*
|
||||
* @param mixed[] $arguments
|
||||
* @psalm-param list<mixed> $arguments
|
||||
* @phpstan-param list<mixed> $arguments
|
||||
*
|
||||
* @throws BadMethodCallException If the method called is invalid.
|
||||
*/
|
||||
@@ -168,7 +169,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
));
|
||||
}
|
||||
|
||||
/** @psalm-return class-string<T> */
|
||||
/** @return class-string<T> */
|
||||
protected function getEntityName(): string
|
||||
{
|
||||
return $this->entityName;
|
||||
@@ -184,7 +185,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
return $this->em;
|
||||
}
|
||||
|
||||
/** @psalm-return ClassMetadata<T> */
|
||||
/** @phpstan-return ClassMetadata<T> */
|
||||
protected function getClassMetadata(): ClassMetadata
|
||||
{
|
||||
return $this->class;
|
||||
@@ -194,7 +195,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
* Select all elements from a selectable that match the expression and
|
||||
* return a new collection containing these elements.
|
||||
*
|
||||
* @psalm-return AbstractLazyCollection<int, T>&Selectable<int, T>
|
||||
* @phpstan-return AbstractLazyCollection<int, T>&Selectable<int, T>
|
||||
*/
|
||||
public function matching(Criteria $criteria): AbstractLazyCollection&Selectable
|
||||
{
|
||||
@@ -208,7 +209,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
*
|
||||
* @param string $method The method to call
|
||||
* @param string $by The property name used as condition
|
||||
* @psalm-param list<mixed> $arguments The arguments to pass at method call
|
||||
* @phpstan-param list<mixed> $arguments The arguments to pass at method call
|
||||
*
|
||||
* @throws InvalidMagicMethodCall If the method called is invalid or the
|
||||
* requested field/association does not exist.
|
||||
|
||||
@@ -38,7 +38,7 @@ class ListenersInvoker
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param string $eventName The entity lifecycle event.
|
||||
*
|
||||
* @psalm-return int-mask-of<self::INVOKE_*> Bitmask of subscribed event systems.
|
||||
* @phpstan-return int-mask-of<self::INVOKE_*> Bitmask of subscribed event systems.
|
||||
*/
|
||||
public function getSubscribedSystems(ClassMetadata $metadata, string $eventName): int
|
||||
{
|
||||
@@ -66,7 +66,7 @@ class ListenersInvoker
|
||||
* @param string $eventName The entity lifecycle event.
|
||||
* @param object $entity The Entity on which the event occurred.
|
||||
* @param EventArgs $event The Event args.
|
||||
* @psalm-param int-mask-of<self::INVOKE_*> $invoke Bitmask to invoke listeners.
|
||||
* @phpstan-param int-mask-of<self::INVOKE_*> $invoke Bitmask to invoke listeners.
|
||||
*/
|
||||
public function invoke(
|
||||
ClassMetadata $metadata,
|
||||
|
||||
@@ -24,7 +24,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
|
||||
/**
|
||||
* @param mixed[][] $changeSet
|
||||
* @psalm-param array<string, array{mixed, mixed}|PersistentCollection> $changeSet
|
||||
* @phpstan-param array<string, array{mixed, mixed}|PersistentCollection> $changeSet
|
||||
*/
|
||||
public function __construct(object $entity, EntityManagerInterface $em, array &$changeSet)
|
||||
{
|
||||
@@ -37,7 +37,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
* Retrieves entity changeset.
|
||||
*
|
||||
* @return mixed[][]
|
||||
* @psalm-return array<string, array{mixed, mixed}|PersistentCollection>
|
||||
* @phpstan-return array<string, array{mixed, mixed}|PersistentCollection>
|
||||
*/
|
||||
public function getEntityChangeSet(): array
|
||||
{
|
||||
|
||||
@@ -103,16 +103,14 @@ final class Events
|
||||
* The onFlush event occurs when the EntityManager#flush() operation is invoked,
|
||||
* after any changes to managed entities have been determined but before any
|
||||
* actual database operations are executed. The event is only raised if there is
|
||||
* actually something to do for the underlying UnitOfWork. If nothing needs to be done,
|
||||
* the onFlush event is not raised.
|
||||
* actually something to do for the underlying UnitOfWork.
|
||||
*/
|
||||
public const onFlush = 'onFlush';
|
||||
|
||||
/**
|
||||
* The postFlush event occurs when the EntityManager#flush() operation is invoked and
|
||||
* after all actual database operations are executed successfully. The event is only raised if there is
|
||||
* actually something to do for the underlying UnitOfWork. If nothing needs to be done,
|
||||
* the postFlush event is not raised. The event won't be raised if an error occurs during the
|
||||
* actually something to do for the underlying UnitOfWork. The event won't be raised if an error occurs during the
|
||||
* flush operation.
|
||||
*/
|
||||
public const postFlush = 'postFlush';
|
||||
|
||||
17
src/Exception/DuplicateFieldException.php
Normal file
17
src/Exception/DuplicateFieldException.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Exception;
|
||||
|
||||
use LogicException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
class DuplicateFieldException extends LogicException implements ORMException
|
||||
{
|
||||
public static function create(string $argName, string $columnName): self
|
||||
{
|
||||
return new self(sprintf('Name "%s" for "%s" already in use.', $argName, $columnName));
|
||||
}
|
||||
}
|
||||
17
src/Exception/NoMatchingPropertyException.php
Normal file
17
src/Exception/NoMatchingPropertyException.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Exception;
|
||||
|
||||
use LogicException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
class NoMatchingPropertyException extends LogicException implements ORMException
|
||||
{
|
||||
public static function create(string $property): self
|
||||
{
|
||||
return new self(sprintf('Column name "%s" does not match any property name. Consider aliasing it to the name of an existing property.', $property));
|
||||
}
|
||||
}
|
||||
@@ -18,18 +18,20 @@ use Generator;
|
||||
use LogicException;
|
||||
use ReflectionClass;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use function end;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function ksort;
|
||||
|
||||
/**
|
||||
* Base class for all hydrators. A hydrator is a class that provides some form
|
||||
* of transformation of an SQL result set into another structure.
|
||||
*
|
||||
* @psalm-consistent-constructor
|
||||
* @phpstan-consistent-constructor
|
||||
*/
|
||||
abstract class AbstractHydrator
|
||||
{
|
||||
@@ -86,7 +88,7 @@ abstract class AbstractHydrator
|
||||
/**
|
||||
* Initiates a row-by-row hydration.
|
||||
*
|
||||
* @psalm-param array<string, mixed> $hints
|
||||
* @phpstan-param array<string, mixed> $hints
|
||||
*
|
||||
* @return Generator<array-key, mixed>
|
||||
*
|
||||
@@ -153,7 +155,7 @@ abstract class AbstractHydrator
|
||||
/**
|
||||
* Hydrates all rows returned by the passed statement instance at once.
|
||||
*
|
||||
* @psalm-param array<string, string> $hints
|
||||
* @phpstan-param array<string, string> $hints
|
||||
*/
|
||||
public function hydrateAll(Result $stmt, ResultSetMapping $resultSetMapping, array $hints = []): mixed
|
||||
{
|
||||
@@ -242,25 +244,37 @@ abstract class AbstractHydrator
|
||||
* the values applied. Scalar values are kept in a specific key 'scalars'.
|
||||
*
|
||||
* @param mixed[] $data SQL Result Row.
|
||||
* @psalm-param array<string, string> $id Dql-Alias => ID-Hash.
|
||||
* @psalm-param array<string, bool> $nonemptyComponents Does this DQL-Alias has at least one non NULL value?
|
||||
* @phpstan-param array<string, string> $id Dql-Alias => ID-Hash.
|
||||
* @phpstan-param array<string, bool> $nonemptyComponents Does this DQL-Alias has at least one non NULL value?
|
||||
*
|
||||
* @return array<string, array<string, mixed>> An array with all the fields
|
||||
* (name => value) of the data
|
||||
* row, grouped by their
|
||||
* component alias.
|
||||
* @psalm-return array{
|
||||
* @phpstan-return array{
|
||||
* data: array<array-key, array>,
|
||||
* newObjects?: array<array-key, array{
|
||||
* class: mixed,
|
||||
* args?: array
|
||||
* class: ReflectionClass,
|
||||
* args: array,
|
||||
* obj: object
|
||||
* }>,
|
||||
* scalars?: array
|
||||
* }
|
||||
*/
|
||||
protected function gatherRowData(array $data, array &$id, array &$nonemptyComponents): array
|
||||
{
|
||||
$rowData = ['data' => []];
|
||||
$rowData = ['data' => [], 'newObjects' => []];
|
||||
|
||||
foreach ($this->rsm->newObjectMappings as $mapping) {
|
||||
if (! array_key_exists($mapping['objIndex'], $this->rsm->newObject)) {
|
||||
$this->rsm->newObject[$mapping['objIndex']] = $mapping['className'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->rsm->newObject as $objIndex => $newObject) {
|
||||
$rowData['newObjects'][$objIndex]['class'] = new ReflectionClass($newObject);
|
||||
$rowData['newObjects'][$objIndex]['args'] = [];
|
||||
}
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$cacheKeyInfo = $this->hydrateColumnInfo($key);
|
||||
@@ -281,7 +295,6 @@ abstract class AbstractHydrator
|
||||
$value = $this->buildEnum($value, $cacheKeyInfo['enumType']);
|
||||
}
|
||||
|
||||
$rowData['newObjects'][$objIndex]['class'] = $cacheKeyInfo['class'];
|
||||
$rowData['newObjects'][$objIndex]['args'][$argIndex] = $value;
|
||||
break;
|
||||
|
||||
@@ -335,6 +348,21 @@ abstract class AbstractHydrator
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->resultSetMapping()->nestedNewObjectArguments as ['ownerIndex' => $ownerIndex, 'argIndex' => $argIndex, 'argAlias' => $argAlias]) {
|
||||
if (array_key_exists($argAlias, $rowData['newObjects'])) {
|
||||
ksort($rowData['newObjects'][$argAlias]['args']);
|
||||
$rowData['newObjects'][$ownerIndex]['args'][$argIndex] = $rowData['newObjects'][$argAlias]['class']->newInstanceArgs($rowData['newObjects'][$argAlias]['args']);
|
||||
unset($rowData['newObjects'][$argAlias]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rowData['newObjects'] as $objIndex => $newObject) {
|
||||
ksort($rowData['newObjects'][$objIndex]['args']);
|
||||
$obj = $rowData['newObjects'][$objIndex]['class']->newInstanceArgs($rowData['newObjects'][$objIndex]['args']);
|
||||
|
||||
$rowData['newObjects'][$objIndex]['obj'] = $obj;
|
||||
}
|
||||
|
||||
return $rowData;
|
||||
}
|
||||
|
||||
@@ -347,10 +375,10 @@ abstract class AbstractHydrator
|
||||
* of elements as before.
|
||||
*
|
||||
* @param mixed[] $data
|
||||
* @psalm-param array<string, mixed> $data
|
||||
* @phpstan-param array<string, mixed> $data
|
||||
*
|
||||
* @return mixed[] The processed row.
|
||||
* @psalm-return array<string, mixed>
|
||||
* @phpstan-return array<string, mixed>
|
||||
*/
|
||||
protected function gatherScalarRowData(array &$data): array
|
||||
{
|
||||
@@ -385,7 +413,7 @@ abstract class AbstractHydrator
|
||||
* @param string $key Column name
|
||||
*
|
||||
* @return mixed[]|null
|
||||
* @psalm-return array<string, mixed>|null
|
||||
* @phpstan-return array<string, mixed>|null
|
||||
*/
|
||||
protected function hydrateColumnInfo(string $key): array|null
|
||||
{
|
||||
@@ -434,7 +462,6 @@ abstract class AbstractHydrator
|
||||
'type' => Type::getType($this->rsm->typeMappings[$key]),
|
||||
'argIndex' => $mapping['argIndex'],
|
||||
'objIndex' => $mapping['objIndex'],
|
||||
'class' => new ReflectionClass($mapping['className']),
|
||||
'enumType' => $this->rsm->enumMappings[$key] ?? null,
|
||||
];
|
||||
|
||||
@@ -482,7 +509,7 @@ abstract class AbstractHydrator
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @psalm-return non-empty-list<string>
|
||||
* @phpstan-return non-empty-list<string>
|
||||
*/
|
||||
private function getDiscriminatorValues(ClassMetadata $classMetadata): array
|
||||
{
|
||||
|
||||
@@ -214,9 +214,8 @@ class ArrayHydrator extends AbstractHydrator
|
||||
$scalarCount = (isset($rowData['scalars']) ? count($rowData['scalars']) : 0);
|
||||
|
||||
foreach ($rowData['newObjects'] as $objIndex => $newObject) {
|
||||
$class = $newObject['class'];
|
||||
$args = $newObject['args'];
|
||||
$obj = $class->newInstanceArgs($args);
|
||||
$args = $newObject['args'];
|
||||
$obj = $newObject['obj'];
|
||||
|
||||
if (count($args) === $scalarCount || ($scalarCount === 0 && count($rowData['newObjects']) === 1)) {
|
||||
$result[$resultKey] = $obj;
|
||||
|
||||
@@ -64,4 +64,9 @@ class HydrationException extends Exception implements ORMException
|
||||
implode('", "', $discrValues),
|
||||
));
|
||||
}
|
||||
|
||||
public static function partialObjectHydrationDisallowed(): self
|
||||
{
|
||||
return new self('Hydration of entity objects is not allowed when DQL PARTIAL keyword is used.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* Gets an entity instance.
|
||||
*
|
||||
* @param string $dqlAlias The DQL alias of the entity's class.
|
||||
* @psalm-param array<string, mixed> $data The instance data.
|
||||
* @phpstan-param array<string, mixed> $data The instance data.
|
||||
*
|
||||
* @throws HydrationException
|
||||
*/
|
||||
@@ -265,8 +265,8 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param class-string $className
|
||||
* @psalm-param array<string, mixed> $data
|
||||
* @param class-string $className
|
||||
* @phpstan-param array<string, mixed> $data
|
||||
*/
|
||||
private function getEntityFromIdentityMap(string $className, array $data): object|bool
|
||||
{
|
||||
@@ -356,11 +356,15 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$parentObject = $this->resultPointers[$parentAlias];
|
||||
} else {
|
||||
// Parent object of relation not found, mark as not-fetched again
|
||||
$element = $this->getEntity($data, $dqlAlias);
|
||||
if (isset($nonemptyComponents[$dqlAlias])) {
|
||||
$element = $this->getEntity($data, $dqlAlias);
|
||||
|
||||
// Update result pointer and provide initial fetch data for parent
|
||||
$this->resultPointers[$dqlAlias] = $element;
|
||||
$rowData['data'][$parentAlias][$relationField] = $element;
|
||||
// Update result pointer and provide initial fetch data for parent
|
||||
$this->resultPointers[$dqlAlias] = $element;
|
||||
$rowData['data'][$parentAlias][$relationField] = $element;
|
||||
} else {
|
||||
$element = null;
|
||||
}
|
||||
|
||||
// Mark as not-fetched again
|
||||
unset($this->hints['fetched'][$parentAlias][$relationField]);
|
||||
@@ -552,9 +556,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$scalarCount = (isset($rowData['scalars']) ? count($rowData['scalars']) : 0);
|
||||
|
||||
foreach ($rowData['newObjects'] as $objIndex => $newObject) {
|
||||
$class = $newObject['class'];
|
||||
$args = $newObject['args'];
|
||||
$obj = $class->newInstanceArgs($args);
|
||||
$obj = $newObject['obj'];
|
||||
|
||||
if ($scalarCount === 0 && count($rowData['newObjects']) === 1) {
|
||||
$result[$resultKey] = $obj;
|
||||
|
||||
@@ -17,6 +17,7 @@ use function array_search;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function key;
|
||||
use function reset;
|
||||
use function sprintf;
|
||||
@@ -138,14 +139,21 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
if ($value !== null && isset($cacheKeyInfo['enumType'])) {
|
||||
$originalValue = $value;
|
||||
$originalValue = $currentValue = $value;
|
||||
try {
|
||||
$value = $this->buildEnum($originalValue, $cacheKeyInfo['enumType']);
|
||||
if (! is_array($originalValue)) {
|
||||
$value = $this->buildEnum($originalValue, $cacheKeyInfo['enumType']);
|
||||
} else {
|
||||
$value = [];
|
||||
foreach ($originalValue as $i => $currentValue) {
|
||||
$value[$i] = $this->buildEnum($currentValue, $cacheKeyInfo['enumType']);
|
||||
}
|
||||
}
|
||||
} catch (ValueError $e) {
|
||||
throw MappingException::invalidEnumValue(
|
||||
$entityName,
|
||||
$cacheKeyInfo['fieldName'],
|
||||
(string) $originalValue,
|
||||
(string) $currentValue,
|
||||
$cacheKeyInfo['enumType'],
|
||||
$e,
|
||||
);
|
||||
|
||||
@@ -29,7 +29,7 @@ trait NoUnknownNamedArguments
|
||||
* @param TItem[] $parameter
|
||||
*
|
||||
* @template TItem
|
||||
* @psalm-assert list<TItem> $parameter
|
||||
* @phpstan-assert list<TItem> $parameter
|
||||
*/
|
||||
private static function validateVariadicParameter(array $parameter): void
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user