mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 06:52:09 +01:00
Compare commits
502 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79bff0f072 | ||
|
|
77b579287c | ||
|
|
27c33cf88d | ||
|
|
6068b61a0d | ||
|
|
00024f7d88 | ||
|
|
44c92377a0 | ||
|
|
255612a1ff | ||
|
|
331f8b52cb | ||
|
|
b2faba62b7 | ||
|
|
da426a0036 | ||
|
|
1891a76f13 | ||
|
|
6bb30e1cee | ||
|
|
6336eb5d5d | ||
|
|
b8f404abcf | ||
|
|
3e8490a792 | ||
|
|
14bb034fe4 | ||
|
|
afc0aab61a | ||
|
|
3e784c1d9a | ||
|
|
e1d7a13a5e | ||
|
|
4262eb495b | ||
|
|
ca49533d3e | ||
|
|
8275471110 | ||
|
|
afd683bdb8 | ||
|
|
fe6e5a67f8 | ||
|
|
b20a66dcdd | ||
|
|
0db02df3aa | ||
|
|
dc46af27ed | ||
|
|
05ab22710b | ||
|
|
d3b47d2cbb | ||
|
|
026f5bfe1b | ||
|
|
6af7de38e1 | ||
|
|
0b0f2f4d86 | ||
|
|
0780b5a6b1 | ||
|
|
71b1831351 | ||
|
|
63d9a898ec | ||
|
|
0bd839a720 | ||
|
|
b65004fc26 | ||
|
|
d2418ab074 | ||
|
|
39a05e31c9 | ||
|
|
7376adede8 | ||
|
|
ab156a551c | ||
|
|
59f7f6793d | ||
|
|
0fc9208d71 | ||
|
|
fd9e572424 | ||
|
|
76490f2c99 | ||
|
|
2148940290 | ||
|
|
d3538095fd | ||
|
|
0c1bf14729 | ||
|
|
3b8c23c51d | ||
|
|
60d4ea694a | ||
|
|
e923bbc932 | ||
|
|
8cbd34c666 | ||
|
|
f8bbdc40b0 | ||
|
|
8bdefef6d1 | ||
|
|
0f8730a6e5 | ||
|
|
62477b5d42 | ||
|
|
12116aa3c2 | ||
|
|
0aeddd0592 | ||
|
|
2491c4b20d | ||
|
|
08d6167243 | ||
|
|
765a9c43e6 | ||
|
|
d4e9276e79 | ||
|
|
cee74faa97 | ||
|
|
9ae2181185 | ||
|
|
3e25efd72b | ||
|
|
47496ed882 | ||
|
|
492745d710 | ||
|
|
67419cf951 | ||
|
|
1237f5c909 | ||
|
|
609e616f2d | ||
|
|
4016d6ba4b | ||
|
|
dcdd46251e | ||
|
|
3d98b43561 | ||
|
|
9f3f70944a | ||
|
|
05e07c0ae0 | ||
|
|
fea42ab984 | ||
|
|
fcd9dede2e | ||
|
|
7c347b85c1 | ||
|
|
458b040d93 | ||
|
|
262c396639 | ||
|
|
396636a2c2 | ||
|
|
78dd074266 | ||
|
|
ff22a00fcf | ||
|
|
02e8ff9663 | ||
|
|
01fd55e9ea | ||
|
|
2e75a7f1c1 | ||
|
|
152b0e3d65 | ||
|
|
9d11fdd3da | ||
|
|
87f1ba74e0 | ||
|
|
f357a33d23 | ||
|
|
ee70178314 | ||
|
|
ab148d3d9d | ||
|
|
3924c38fab | ||
|
|
9814078a2c | ||
|
|
6de5684fd9 | ||
|
|
c142503a52 | ||
|
|
01c178b297 | ||
|
|
ffa50a777f | ||
|
|
649048f745 | ||
|
|
15537bc218 | ||
|
|
bc95c7c08d | ||
|
|
6982c8ab9d | ||
|
|
e767d2dbeb | ||
|
|
3df11d518c | ||
|
|
c1becd54e6 | ||
|
|
e4d7df29c2 | ||
|
|
d65b6a6a10 | ||
|
|
3d8afbb7b2 | ||
|
|
736f6bc97f | ||
|
|
608705427e | ||
|
|
f0562f4120 | ||
|
|
9f19310f27 | ||
|
|
e38278bfca | ||
|
|
62f2cff218 | ||
|
|
cdd774906b | ||
|
|
96776e091d | ||
|
|
f7470d8a3f | ||
|
|
2c41cc7f1c | ||
|
|
f18de9d569 | ||
|
|
37f76a8381 | ||
|
|
a6c1e63a60 | ||
|
|
b62292256a | ||
|
|
b138395194 | ||
|
|
6881cdff4c | ||
|
|
dede2d775a | ||
|
|
c502190712 | ||
|
|
5bff0919a7 | ||
|
|
9ef0f5301b | ||
|
|
4989ca6f15 | ||
|
|
32d1e97ce7 | ||
|
|
ca8147b148 | ||
|
|
c8ebea77f0 | ||
|
|
23f22860f1 | ||
|
|
b24586b1b5 | ||
|
|
0ed46303cc | ||
|
|
6e351b699c | ||
|
|
9e5442a892 | ||
|
|
7d8e51c934 | ||
|
|
2f8f1cfcb8 | ||
|
|
fe5ee705db | ||
|
|
01774c035c | ||
|
|
0511a9f790 | ||
|
|
0e3d5e8c82 | ||
|
|
72ffb3bfbf | ||
|
|
2e9a1adc23 | ||
|
|
6f83166266 | ||
|
|
ffd3f50ad7 | ||
|
|
483b45d449 | ||
|
|
1220edf953 | ||
|
|
7e4693d629 | ||
|
|
59938cae57 | ||
|
|
298dc9bb6a | ||
|
|
da67f323e0 | ||
|
|
63635cad0e | ||
|
|
a0d401b688 | ||
|
|
6acbadfbbe | ||
|
|
c64dcb4d38 | ||
|
|
3304290b21 | ||
|
|
1865717721 | ||
|
|
828b06e20f | ||
|
|
c2b844d2e3 | ||
|
|
dd4e8fe78f | ||
|
|
4f36f0129a | ||
|
|
b45d5329f8 | ||
|
|
c1047b30e3 | ||
|
|
f71aa73ef1 | ||
|
|
aa62efa30a | ||
|
|
f71956f001 | ||
|
|
7cc210424c | ||
|
|
4fd9e94819 | ||
|
|
587caf88a7 | ||
|
|
1e33b775d3 | ||
|
|
96f9b29573 | ||
|
|
c6207b1793 | ||
|
|
8c92903430 | ||
|
|
8616a98023 | ||
|
|
9a55cf4f30 | ||
|
|
9d680a6de4 | ||
|
|
7602a5341c | ||
|
|
7a59281157 | ||
|
|
214b1ad739 | ||
|
|
5def068fe9 | ||
|
|
693acbf812 | ||
|
|
28d9472a38 | ||
|
|
cf11f1e453 | ||
|
|
c6955ec056 | ||
|
|
c1ce2bb687 | ||
|
|
6863272943 | ||
|
|
eae6577ce2 | ||
|
|
5f6896a2f9 | ||
|
|
e3106d439d | ||
|
|
930a790a5a | ||
|
|
40aa44914f | ||
|
|
7c8a528914 | ||
|
|
3b7de17f2e | ||
|
|
40fedadecf | ||
|
|
0d97a44f28 | ||
|
|
c472a1535d | ||
|
|
8afaa63d73 | ||
|
|
2ad720b304 | ||
|
|
64cd5cad20 | ||
|
|
f1a8ee175c | ||
|
|
d3e1440175 | ||
|
|
a9bd00a70b | ||
|
|
a939dc2e0d | ||
|
|
758de75b45 | ||
|
|
1ff63be779 | ||
|
|
f8186b1203 | ||
|
|
2d5d129ee1 | ||
|
|
28dd32790f | ||
|
|
4f3a5c5514 | ||
|
|
6641989e35 | ||
|
|
048e308241 | ||
|
|
8ca72a4e96 | ||
|
|
daf74b74b5 | ||
|
|
4274dac8a2 | ||
|
|
ac19b21a71 | ||
|
|
c6db9feade | ||
|
|
c1af765960 | ||
|
|
86d847edb8 | ||
|
|
5f3551852f | ||
|
|
8144cad07c | ||
|
|
70fd68cf7f | ||
|
|
437259556c | ||
|
|
e7e2fef56c | ||
|
|
3e34b8e86a | ||
|
|
7d950aba62 | ||
|
|
8ad560c34d | ||
|
|
ccfb620f31 | ||
|
|
94c4d48ae5 | ||
|
|
cb8a76ba3a | ||
|
|
2ca63df90c | ||
|
|
0d4413c248 | ||
|
|
a7a14cffaf | ||
|
|
cdc52b2a9e | ||
|
|
c5e2f3fb23 | ||
|
|
48434f4c53 | ||
|
|
200a505f36 | ||
|
|
17d7814fdc | ||
|
|
8fe1200edf | ||
|
|
f7d4e379bc | ||
|
|
c164ae434f | ||
|
|
ceb04bf3f6 | ||
|
|
21e9fcbfbb | ||
|
|
ed9ba16ff4 | ||
|
|
db456976ed | ||
|
|
2d9091778f | ||
|
|
17059e5265 | ||
|
|
680a9ef632 | ||
|
|
9d5f112c7e | ||
|
|
b7423c96cf | ||
|
|
c91c3a3b1d | ||
|
|
42a693c0d3 | ||
|
|
fc1bf3b815 | ||
|
|
b6b342cada | ||
|
|
28735afae3 | ||
|
|
0f229fbb4b | ||
|
|
bea4814d55 | ||
|
|
85c13edc80 | ||
|
|
03cc07e4d7 | ||
|
|
397358c308 | ||
|
|
ac37a87a3d | ||
|
|
238c15952c | ||
|
|
613f52db5a | ||
|
|
cf5503b0d8 | ||
|
|
78fee8ea5c | ||
|
|
0c73cf93fa | ||
|
|
fdc88ba236 | ||
|
|
c49bf58682 | ||
|
|
ae5e9c8c6c | ||
|
|
c03ed691d4 | ||
|
|
ce844d94a0 | ||
|
|
1a2826d147 | ||
|
|
05760f9454 | ||
|
|
26af013842 | ||
|
|
c1f7a60c5b | ||
|
|
d1d13d5956 | ||
|
|
4f8dde2d1e | ||
|
|
e3c320c705 | ||
|
|
5a541b8b3a | ||
|
|
9fb9cc46e4 | ||
|
|
c322c71cd4 | ||
|
|
3c733a2fee | ||
|
|
5984ad586a | ||
|
|
ee2c3a506b | ||
|
|
781ed30926 | ||
|
|
04694a9f7b | ||
|
|
257c5094c4 | ||
|
|
b521e89b20 | ||
|
|
831232e05e | ||
|
|
66e0e92816 | ||
|
|
a6a94cdefd | ||
|
|
a774cedb24 | ||
|
|
6b8207bb11 | ||
|
|
3d3b5b51cd | ||
|
|
5b2060e25f | ||
|
|
760616291b | ||
|
|
64444dcfd5 | ||
|
|
c5e5742744 | ||
|
|
8584da8fdc | ||
|
|
eb2cd5375c | ||
|
|
de7140e105 | ||
|
|
07bb0def60 | ||
|
|
39e35fc06c | ||
|
|
7f061c3870 | ||
|
|
74495711fb | ||
|
|
97a7cb8d2f | ||
|
|
85d66de9df | ||
|
|
1b98be31ce | ||
|
|
61f2752a80 | ||
|
|
f3371e1773 | ||
|
|
6476894dc4 | ||
|
|
8b3a6dfbbb | ||
|
|
5634c3ccee | ||
|
|
a93d7d22d8 | ||
|
|
677e0a4ed3 | ||
|
|
8cf161d8bc | ||
|
|
e0052390e1 | ||
|
|
8c6419e0e0 | ||
|
|
6f5ce1aca2 | ||
|
|
98e7a53b42 | ||
|
|
3aaaf37dfb | ||
|
|
154a4652ee | ||
|
|
ae7489ff19 | ||
|
|
0f32569a7a | ||
|
|
d99f74c704 | ||
|
|
a2990e1a0a | ||
|
|
d355c4a990 | ||
|
|
88c395c488 | ||
|
|
256d6cb0d7 | ||
|
|
62ca8424d8 | ||
|
|
3f2209a571 | ||
|
|
1ee01f4473 | ||
|
|
8a9ed138a8 | ||
|
|
e714b1a2fc | ||
|
|
ec0bf05853 | ||
|
|
dc58aa3ea1 | ||
|
|
23b74e4f8b | ||
|
|
d2b699e6f5 | ||
|
|
0338d69324 | ||
|
|
a1fdc6eb6e | ||
|
|
d583460d63 | ||
|
|
2c01dac173 | ||
|
|
137ecb491a | ||
|
|
79d4cfdce8 | ||
|
|
f38ee09082 | ||
|
|
6ab858a5c5 | ||
|
|
3dca27ce0d | ||
|
|
224ff9710d | ||
|
|
e19704e1f8 | ||
|
|
41ea59ac66 | ||
|
|
e605e6d569 | ||
|
|
9437675d3b | ||
|
|
5301b99533 | ||
|
|
63409d638c | ||
|
|
d68c1dcd6d | ||
|
|
00c7b70211 | ||
|
|
68c71521e7 | ||
|
|
a2ea72c763 | ||
|
|
1492b01093 | ||
|
|
9b9160b206 | ||
|
|
6deec3655b | ||
|
|
7f40422d21 | ||
|
|
e67fa5388b | ||
|
|
80053336c9 | ||
|
|
dddcc507ef | ||
|
|
b41d9da88d | ||
|
|
c04bfb78b7 | ||
|
|
8a5dfc86d4 | ||
|
|
79e103c07e | ||
|
|
68b797161e | ||
|
|
e17b31ee68 | ||
|
|
5afadf163a | ||
|
|
ac87e6e7dc | ||
|
|
edfaa37228 | ||
|
|
ea056e98ba | ||
|
|
016d9d2074 | ||
|
|
bab5771e98 | ||
|
|
ee919d6231 | ||
|
|
04c390693a | ||
|
|
49293c4d48 | ||
|
|
8d9e2e7d4e | ||
|
|
ed543a205c | ||
|
|
a96697e436 | ||
|
|
60ff966d54 | ||
|
|
b1ec1da8e6 | ||
|
|
6cfe0883f0 | ||
|
|
33684253c3 | ||
|
|
76852cfef3 | ||
|
|
3bd89caf36 | ||
|
|
eb2e7d959c | ||
|
|
a4b20356f4 | ||
|
|
2550b2d1de | ||
|
|
e94e1ab126 | ||
|
|
cd56fe54bb | ||
|
|
982ef7ac56 | ||
|
|
19e1a64a91 | ||
|
|
082e776e91 | ||
|
|
bbde41f712 | ||
|
|
8c0994f35f | ||
|
|
3d390bc053 | ||
|
|
16f1be7f10 | ||
|
|
bc904f6a0c | ||
|
|
cddf985a7d | ||
|
|
2e9ca50007 | ||
|
|
275975a444 | ||
|
|
2088a469cb | ||
|
|
3f13f119e2 | ||
|
|
d444a79bb0 | ||
|
|
01dae555bf | ||
|
|
d9049d8ef5 | ||
|
|
1ad46527b6 | ||
|
|
1334162a56 | ||
|
|
68ec3ebaa3 | ||
|
|
4f4ed2f242 | ||
|
|
a4b794db4f | ||
|
|
79cc70a62f | ||
|
|
4e6b5a1b0b | ||
|
|
21b144fff9 | ||
|
|
658940de38 | ||
|
|
ad487370f5 | ||
|
|
259f83b549 | ||
|
|
4a24860dcf | ||
|
|
116cdf8661 | ||
|
|
7eeea7d66c | ||
|
|
f96e812438 | ||
|
|
d1b4aa013a | ||
|
|
dda313871d | ||
|
|
f7584df83c | ||
|
|
28b2591694 | ||
|
|
528b8837e1 | ||
|
|
615566507c | ||
|
|
9b1cb60cbc | ||
|
|
9bf407f336 | ||
|
|
4fb044d5f6 | ||
|
|
1d0e365401 | ||
|
|
c12daf5206 | ||
|
|
2a953c5e2b | ||
|
|
abc6a40ccb | ||
|
|
73e68f3c7d | ||
|
|
73777d0bd4 | ||
|
|
e89b58a13f | ||
|
|
2b94ec18b9 | ||
|
|
f7030d1844 | ||
|
|
8d7b4d8d17 | ||
|
|
f53d35b74a | ||
|
|
2a662149f4 | ||
|
|
350597beb0 | ||
|
|
8dc17b2851 | ||
|
|
ee9dd474de | ||
|
|
0a4a11b6e4 | ||
|
|
a7406cc26d | ||
|
|
f11adcb622 | ||
|
|
1e4b88d456 | ||
|
|
eb5dd3f34f | ||
|
|
25066f801c | ||
|
|
a0f5b4c9a3 | ||
|
|
8b5148a7a8 | ||
|
|
22198f7c19 | ||
|
|
9cf5593759 | ||
|
|
b5c0e0154f | ||
|
|
dbf26dbf90 | ||
|
|
9b09cd03c0 | ||
|
|
2c489fb8b3 | ||
|
|
42a36e19a5 | ||
|
|
f46d8a1742 | ||
|
|
1eb67b7ca1 | ||
|
|
00b29a13f2 | ||
|
|
a22e0fda8e | ||
|
|
b58946a11f | ||
|
|
d973867dc0 | ||
|
|
ac5a17da2e | ||
|
|
f4bbf8e1d0 | ||
|
|
95a0000446 | ||
|
|
b2a09b9c4e | ||
|
|
3695d5793d | ||
|
|
9674168572 | ||
|
|
80aec02fd7 | ||
|
|
637cd6e405 | ||
|
|
9430d56d78 | ||
|
|
a4e71b8df7 | ||
|
|
f20955901a | ||
|
|
54c36d2a55 | ||
|
|
ea7cc64911 | ||
|
|
22947da46b | ||
|
|
2928b9331a | ||
|
|
fdd84a2290 | ||
|
|
8c1ad6f0c5 | ||
|
|
a5cb7c26c5 | ||
|
|
f8b5ef03d5 | ||
|
|
e80f03c5d8 | ||
|
|
c1d61802cd | ||
|
|
ca8631c172 | ||
|
|
518d16b9cb | ||
|
|
7679fc0f4f | ||
|
|
c5ef72d060 | ||
|
|
cbab4d6a14 | ||
|
|
5733eced42 | ||
|
|
0917109c50 | ||
|
|
615eb926f4 | ||
|
|
d734ab38fa | ||
|
|
0446f5b4b5 |
@@ -12,41 +12,17 @@
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "3.5",
|
||||
"branchName": "3.5.x",
|
||||
"slug": "3.5",
|
||||
"name": "3.7",
|
||||
"branchName": "3.7.x",
|
||||
"slug": "3.7",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "3.4",
|
||||
"branchName": "3.4.x",
|
||||
"slug": "3.4",
|
||||
"name": "3.6",
|
||||
"branchName": "3.6.x",
|
||||
"slug": "3.6",
|
||||
"current": true
|
||||
},
|
||||
{
|
||||
"name": "3.3",
|
||||
"branchName": "3.3.x",
|
||||
"slug": "3.3",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "3.2",
|
||||
"branchName": "3.2.x",
|
||||
"slug": "3.2",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "3.1",
|
||||
"branchName": "3.1.x",
|
||||
"slug": "3.1",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "3.0",
|
||||
"branchName": "3.0.x",
|
||||
"slug": "3.0",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.21",
|
||||
"branchName": "2.21.x",
|
||||
@@ -61,63 +37,33 @@
|
||||
},
|
||||
{
|
||||
"name": "2.19",
|
||||
"branchName": "2.19.x",
|
||||
"slug": "2.19",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.18",
|
||||
"branchName": "2.18.x",
|
||||
"slug": "2.18",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.17",
|
||||
"branchName": "2.17.x",
|
||||
"slug": "2.17",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.16",
|
||||
"branchName": "2.16.x",
|
||||
"slug": "2.16",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.15",
|
||||
"branchName": "2.15.x",
|
||||
"slug": "2.15",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.14",
|
||||
"branchName": "2.14.x",
|
||||
"slug": "2.14",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.13",
|
||||
"branchName": "2.13.x",
|
||||
"slug": "2.13",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.12",
|
||||
"branchName": "2.12.x",
|
||||
"slug": "2.12",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.11",
|
||||
"branchName": "2.11.x",
|
||||
"slug": "2.11",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.10",
|
||||
"branchName": "2.10.x",
|
||||
"slug": "2.10",
|
||||
"maintained": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -11,11 +11,10 @@ build.properties.dev export-ignore
|
||||
build.xml export-ignore
|
||||
CONTRIBUTING.md export-ignore
|
||||
phpunit.xml.dist export-ignore
|
||||
run-all.sh export-ignore
|
||||
phpcs.xml.dist export-ignore
|
||||
phpbench.json export-ignore
|
||||
phpstan.neon export-ignore
|
||||
phpstan-baseline.neon export-ignore
|
||||
phpstan-dbal2.neon export-ignore
|
||||
phpstan-dbal3.neon export-ignore
|
||||
phpstan-params.neon export-ignore
|
||||
phpstan-persistence2.neon export-ignore
|
||||
|
||||
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@7.3.0"
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@13.1.0"
|
||||
|
||||
20
.github/workflows/composer-lint.yml
vendored
Normal file
20
.github/workflows/composer-lint.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: "Composer Lint"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- ".github/workflows/composer-lint.yml"
|
||||
- "composer.json"
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- ".github/workflows/composer-lint.yml"
|
||||
- "composer.json"
|
||||
|
||||
jobs:
|
||||
composer-lint:
|
||||
name: "Composer Lint"
|
||||
uses: "doctrine/.github/.github/workflows/composer-lint.yml@13.1.0"
|
||||
189
.github/workflows/continuous-integration.yml
vendored
189
.github/workflows/continuous-integration.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: "Continuous Integration"
|
||||
name: "CI: PHPUnit"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -25,49 +25,58 @@ env:
|
||||
|
||||
jobs:
|
||||
phpunit-smoke-check:
|
||||
name: "PHPUnit with SQLite"
|
||||
name: >
|
||||
SQLite -
|
||||
${{ format('PHP {0} - DBAL {1} - ext. {2} - proxy {3}',
|
||||
matrix.php-version || 'Ø',
|
||||
matrix.dbal-version || 'Ø',
|
||||
matrix.extension || 'Ø',
|
||||
matrix.proxy || 'Ø'
|
||||
) }}
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
- "8.5"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3.7"
|
||||
extension:
|
||||
- "sqlite3"
|
||||
- "pdo_sqlite"
|
||||
deps:
|
||||
- "highest"
|
||||
native_lazy:
|
||||
- "0"
|
||||
stability:
|
||||
- "stable"
|
||||
include:
|
||||
- php-version: "8.2"
|
||||
- php-version: "8.4"
|
||||
dbal-version: "4@dev"
|
||||
extension: "pdo_sqlite"
|
||||
native_lazy: "0"
|
||||
- php-version: "8.2"
|
||||
stability: "stable"
|
||||
- php-version: "8.4"
|
||||
dbal-version: "4@dev"
|
||||
extension: "sqlite3"
|
||||
native_lazy: "0"
|
||||
- php-version: "8.1"
|
||||
stability: "stable"
|
||||
- php-version: "8.4"
|
||||
dbal-version: "default"
|
||||
deps: "lowest"
|
||||
extension: "pdo_sqlite"
|
||||
native_lazy: "0"
|
||||
stability: "stable"
|
||||
- php-version: "8.4"
|
||||
dbal-version: "default"
|
||||
deps: "highest"
|
||||
extension: "pdo_sqlite"
|
||||
native_lazy: "1"
|
||||
stability: "stable"
|
||||
- php-version: "8.4"
|
||||
dbal-version: "default"
|
||||
deps: "highest"
|
||||
extension: "sqlite3"
|
||||
stability: "dev"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v6"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -79,6 +88,14 @@ jobs:
|
||||
coverage: "pcov"
|
||||
ini-values: "zend.assertions=1, apc.enable_cli=1"
|
||||
|
||||
- name: "Allow dev dependencies"
|
||||
run: |
|
||||
composer config minimum-stability dev
|
||||
composer remove --no-update --dev phpbench/phpbench phpdocumentor/guides-cli
|
||||
composer require --no-update symfony/console:^8 symfony/var-exporter:^8 doctrine/dbal:^4.4
|
||||
composer require --dev --no-update symfony/cache:^8
|
||||
if: "${{ matrix.stability == 'dev' }}"
|
||||
|
||||
- name: "Require specific DBAL version"
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
@@ -93,48 +110,100 @@ jobs:
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage-no-cache.xml"
|
||||
env:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 0
|
||||
ENABLE_NATIVE_LAZY_OBJECTS: ${{ matrix.native_lazy }}
|
||||
|
||||
- name: "Run PHPUnit with Second Level Cache"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --exclude-group performance,non-cacheable,locking_functional --coverage-clover=coverage-cache.xml"
|
||||
- name: "Run PHPUnit with Second Level Cache and PHPUnit 10"
|
||||
run: |
|
||||
vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml \
|
||||
--exclude-group=performance,non-cacheable,locking_functional \
|
||||
--coverage-clover=coverage-cache.xml
|
||||
if: "${{ matrix.php-version == '8.1' }}"
|
||||
env:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 1
|
||||
ENABLE_NATIVE_LAZY_OBJECTS: ${{ matrix.native_lazy }}
|
||||
|
||||
- name: "Run PHPUnit with Second Level Cache and PHPUnit 11+"
|
||||
run: |
|
||||
vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml \
|
||||
--exclude-group=performance \
|
||||
--exclude-group=non-cacheable \
|
||||
--exclude-group=locking_functional \
|
||||
--coverage-clover=coverage-cache.xml
|
||||
if: "${{ matrix.php-version != '8.1' }}"
|
||||
env:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 1
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
uses: "actions/upload-artifact@v7"
|
||||
with:
|
||||
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.deps }}-${{ matrix.native_lazy }}-coverage"
|
||||
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.deps }}-${{ matrix.stability }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
|
||||
|
||||
phpunit-deprecations:
|
||||
name: "PHPUnit (fail on deprecations)"
|
||||
runs-on: "ubuntu-24.04"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v5"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
php-version: "8.5"
|
||||
extensions: "apcu, pdo, sqlite3"
|
||||
coverage: "pcov"
|
||||
ini-values: "zend.assertions=1, apc.enable_cli=1"
|
||||
|
||||
- name: "Allow dev dependencies"
|
||||
run: composer config minimum-stability dev
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
dependency-versions: "highest"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite3.xml --fail-on-deprecation"
|
||||
env:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 0
|
||||
ENABLE_NATIVE_LAZY_OBJECTS: 1
|
||||
|
||||
|
||||
phpunit-postgres:
|
||||
name: "PHPUnit with PostgreSQL"
|
||||
name: >
|
||||
${{ format('PostgreSQL {0} - PHP {1} - DBAL {2} - ext. {3}',
|
||||
matrix.postgres-version || 'Ø',
|
||||
matrix.php-version || 'Ø',
|
||||
matrix.dbal-version || 'Ø',
|
||||
matrix.extension || 'Ø'
|
||||
) }}
|
||||
runs-on: "ubuntu-22.04"
|
||||
needs: "phpunit-smoke-check"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
- "8.5"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3.7"
|
||||
postgres-version:
|
||||
- "17"
|
||||
extension:
|
||||
- pdo_pgsql
|
||||
- pgsql
|
||||
include:
|
||||
- php-version: "8.2"
|
||||
- php-version: "8.4"
|
||||
dbal-version: "4@dev"
|
||||
postgres-version: "14"
|
||||
extension: pdo_pgsql
|
||||
- php-version: "8.2"
|
||||
dbal-version: "3.7"
|
||||
postgres-version: "9.6"
|
||||
- php-version: "8.4"
|
||||
dbal-version: "default"
|
||||
postgres-version: "10"
|
||||
extension: pdo_pgsql
|
||||
|
||||
services:
|
||||
@@ -151,7 +220,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v6"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -176,26 +245,30 @@ jobs:
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
uses: "actions/upload-artifact@v7"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.extension }}-coverage"
|
||||
path: "coverage.xml"
|
||||
|
||||
|
||||
phpunit-mariadb:
|
||||
name: "PHPUnit with MariaDB"
|
||||
name: >
|
||||
${{ format('MariaDB {0} - PHP {1} - DBAL {2} - ext. {3}',
|
||||
matrix.mariadb-version || 'Ø',
|
||||
matrix.php-version || 'Ø',
|
||||
matrix.dbal-version || 'Ø',
|
||||
matrix.extension || 'Ø'
|
||||
) }}
|
||||
runs-on: "ubuntu-22.04"
|
||||
needs: "phpunit-smoke-check"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
- "8.5"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3.7"
|
||||
- "4@dev"
|
||||
mariadb-version:
|
||||
- "11.4"
|
||||
@@ -218,7 +291,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v6"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -243,26 +316,30 @@ jobs:
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
uses: "actions/upload-artifact@v7"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage.xml"
|
||||
|
||||
|
||||
phpunit-mysql:
|
||||
name: "PHPUnit with MySQL"
|
||||
name: >
|
||||
${{ format('MySQL {0} - PHP {1} - DBAL {2} - ext. {3}',
|
||||
matrix.mysql-version || 'Ø',
|
||||
matrix.php-version || 'Ø',
|
||||
matrix.dbal-version || 'Ø',
|
||||
matrix.extension || 'Ø'
|
||||
) }}
|
||||
runs-on: "ubuntu-22.04"
|
||||
needs: "phpunit-smoke-check"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
- "8.5"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3.7"
|
||||
mysql-version:
|
||||
- "5.7"
|
||||
- "8.0"
|
||||
@@ -270,11 +347,11 @@ jobs:
|
||||
- "mysqli"
|
||||
- "pdo_mysql"
|
||||
include:
|
||||
- php-version: "8.2"
|
||||
- php-version: "8.4"
|
||||
dbal-version: "4@dev"
|
||||
mysql-version: "8.0"
|
||||
extension: "mysqli"
|
||||
- php-version: "8.2"
|
||||
- php-version: "8.4"
|
||||
dbal-version: "4@dev"
|
||||
mysql-version: "8.0"
|
||||
extension: "pdo_mysql"
|
||||
@@ -293,7 +370,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v6"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -319,13 +396,27 @@ jobs:
|
||||
env:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 0
|
||||
|
||||
- name: "Run PHPUnit with Second Level Cache"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --exclude-group performance,non-cacheable,locking_functional --coverage-clover=coverage-no-cache.xml"
|
||||
- name: "Run PHPUnit with Second Level Cache and PHPUnit 10"
|
||||
run: |
|
||||
vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml \
|
||||
--exclude-group=performance,non-cacheable,locking_functional \
|
||||
--coverage-clover=coverage-no-cache.xml"
|
||||
if: "${{ matrix.php-version == '8.1' }}"
|
||||
env:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 1
|
||||
- name: "Run PHPUnit with Second Level Cache and PHPUnit 11+"
|
||||
run: |
|
||||
vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml \
|
||||
--exclude-group=performance \
|
||||
--exclude-group=non-cacheable \
|
||||
--exclude-group=locking_functional \
|
||||
--coverage-clover=coverage-no-cache.xml
|
||||
if: "${{ matrix.php-version != '8.1' }}"
|
||||
env:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 1
|
||||
|
||||
- name: "Upload coverage files"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
uses: "actions/upload-artifact@v7"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
@@ -343,12 +434,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v6"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: "Download coverage files"
|
||||
uses: "actions/download-artifact@v4"
|
||||
uses: "actions/download-artifact@v8"
|
||||
with:
|
||||
path: "reports"
|
||||
|
||||
|
||||
2
.github/workflows/documentation.yml
vendored
2
.github/workflows/documentation.yml
vendored
@@ -17,4 +17,4 @@ on:
|
||||
jobs:
|
||||
documentation:
|
||||
name: "Documentation"
|
||||
uses: "doctrine/.github/.github/workflows/documentation.yml@7.3.0"
|
||||
uses: "doctrine/.github/.github/workflows/documentation.yml@13.1.0"
|
||||
|
||||
4
.github/workflows/phpbench.yml
vendored
4
.github/workflows/phpbench.yml
vendored
@@ -32,11 +32,11 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.1"
|
||||
- "8.4"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v6"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.3.0"
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@13.1.0"
|
||||
secrets:
|
||||
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
|
||||
17
.github/workflows/static-analysis.yml
vendored
17
.github/workflows/static-analysis.yml
vendored
@@ -25,17 +25,9 @@ jobs:
|
||||
name: Static Analysis with PHPStan
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- dbal-version: default
|
||||
config: phpstan.neon
|
||||
- dbal-version: 3.8.2
|
||||
config: phpstan-dbal3.neon
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v6"
|
||||
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
@@ -44,13 +36,8 @@ jobs:
|
||||
php-version: "8.4"
|
||||
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@v2
|
||||
|
||||
- name: Run static analysis with phpstan/phpstan
|
||||
run: "vendor/bin/phpstan analyse -c ${{ matrix.config }} --error-format=checkstyle | cs2pr"
|
||||
run: "vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr"
|
||||
|
||||
29
README.md
29
README.md
@@ -1,9 +1,9 @@
|
||||
| [4.0.x][4.0] | [3.5.x][3.5] | [3.4.x][3.4] | [2.21.x][2.21] | [2.20.x][2.20] |
|
||||
| [4.0.x][4.0] | [3.7.x][3.7] | [3.6.x][3.6] | [2.21.x][2.21] | [2.20.x][2.20] |
|
||||
|:------------------------------------------------------:|:------------------------------------------------------:|:------------------------------------------------------:|:--------------------------------------------------------:|:--------------------------------------------------------:|
|
||||
| [![Build status][4.0 image]][4.0] | [![Build status][3.5 image]][3.5] | [![Build status][3.4 image]][3.4] | [![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.5 coverage image]][3.5 coverage] | [![Coverage Status][3.4 coverage image]][3.4 coverage] | [![Coverage Status][2.21 coverage image]][2.21 coverage] | [![Coverage Status][2.20 coverage image]][2.20 coverage] |
|
||||
| [![Build status][4.0 image]][4.0 workflow] | [![Build status][3.7 image]][3.7 workflow] | [![Build status][3.6 image]][3.6 workflow] | [![Build status][2.21 image]][2.21 workflow] | [![Build status][2.20 image]][2.20 workflow] |
|
||||
| [![Coverage Status][4.0 coverage image]][4.0 coverage] | [![Coverage Status][3.7 coverage image]][3.7 coverage] | [![Coverage Status][3.6 coverage image]][3.6 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
|
||||
Doctrine ORM is an object-relational mapper for PHP 8.4+ that provides transparent persistence
|
||||
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
|
||||
is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL),
|
||||
inspired by Hibernate's HQL. This provides developers with a powerful alternative to SQL that maintains flexibility
|
||||
@@ -18,21 +18,26 @@ without requiring unnecessary code duplication.
|
||||
|
||||
[4.0 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=4.0.x
|
||||
[4.0]: https://github.com/doctrine/orm/tree/4.0.x
|
||||
[4.0 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A4.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.5 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.5.x
|
||||
[3.5]: https://github.com/doctrine/orm/tree/3.5.x
|
||||
[3.5 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.5.x/graph/badge.svg
|
||||
[3.5 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.5.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.7 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.7.x
|
||||
[3.7]: https://github.com/doctrine/orm/tree/3.7.x
|
||||
[3.7 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A3.7.x
|
||||
[3.7 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.7.x/graph/badge.svg
|
||||
[3.7 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.7.x
|
||||
[3.6 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.6.x
|
||||
[3.6]: https://github.com/doctrine/orm/tree/3.6.x
|
||||
[3.6 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A3.6.x
|
||||
[3.6 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.6.x/graph/badge.svg
|
||||
[3.6 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.6.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 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A2.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 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A2.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
|
||||
|
||||
434
UPGRADE.md
434
UPGRADE.md
@@ -1,3 +1,399 @@
|
||||
Note about upgrading: Doctrine uses static and runtime mechanisms to raise
|
||||
awareness about deprecated code.
|
||||
|
||||
- Use of `@deprecated` docblock that is detected by IDEs (like PHPStorm) or
|
||||
Static Analysis tools (like Psalm, phpstan)
|
||||
- Use of our low-overhead runtime deprecation API, details:
|
||||
https://github.com/doctrine/deprecations/
|
||||
|
||||
# Upgrade to 4.0
|
||||
|
||||
## BC BREAK: EventManager to EventManagerInterface migration
|
||||
|
||||
The following methods used to return an instance of `Doctrine\Common\EventManager`,
|
||||
and now return an instance of `Doctrine\Common\EventManagerInterface`:
|
||||
|
||||
- `Doctrine\ORM\EntityManager::getEventManager()`
|
||||
- `Doctrine\ORM\EntityManagerDecorator::getEventManager()`
|
||||
- `Doctrine\ORM\EntityManagerInterface::getEventManager()`
|
||||
|
||||
## BC BREAK: Remove `FieldMapping::$default`
|
||||
|
||||
The `default` property of `Doctrine\ORM\Mapping\FieldMapping` has been removed.
|
||||
Use `FieldMapping::$options['default']` instead.
|
||||
|
||||
## BC BREAK: throw on `nullable` on columns that end up being used in a primary key
|
||||
|
||||
Specifying `nullable` on join columns that are part of a primary key is
|
||||
an error and will cause an exception to be thrown.
|
||||
|
||||
## BC BREAK: `Doctrine\ORM\Mapping\LegacyReflectionFields` is removed
|
||||
|
||||
The `Doctrine\ORM\Mapping\LegacyReflectionFields` class has been removed.
|
||||
Also, `Doctrine\ORM\Mapping\ClassMetadata::$reflFields` has been removed, as
|
||||
well as methods depending on it.
|
||||
|
||||
## BC BREAK: Userland lazy objects are no longer supported
|
||||
|
||||
Userland lazy objects are no longer supported.
|
||||
[Native lazy objects](https://www.php.net/manual/en/language.oop5.lazy-objects.php)
|
||||
are used instead.
|
||||
|
||||
## BC BREAK: type declarations on constants
|
||||
|
||||
All constants in the ORM now have type declarations and are final. You may no
|
||||
longer override them in extending types.
|
||||
|
||||
## Remove methods for configuring no longer configurable features
|
||||
|
||||
Since 3.0, lazy ghosts are enabled unconditionally, and so is rejecting ID
|
||||
collisions in the identity map.
|
||||
|
||||
As a consequence, the following methods are removed:
|
||||
|
||||
* `Doctrine\ORM\Configuration::setLazyGhostObjectEnabled()`
|
||||
* `Doctrine\ORM\Configuration::isLazyGhostObjectEnabled()`
|
||||
* `Doctrine\ORM\Configuration::setRejectIdCollisionInIdentityMap()`
|
||||
* `Doctrine\ORM\Configuration::isRejectIdCollisionInIdentityMapEnabled()`
|
||||
|
||||
## BC BREAK: New argument to `NewObjectExpression::dispatch()`
|
||||
|
||||
```diff
|
||||
<?php
|
||||
class NewObjectExpression extends Node
|
||||
{
|
||||
// …
|
||||
|
||||
- public function dispatch(SqlWalker $walker): string
|
||||
+ public function dispatch(SqlWalker $walker, string|null $parentAlias = null): string
|
||||
{
|
||||
// …
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## BC BREAK: New argument to `AbstractEntityPersister::buildCollectionCacheKey()`
|
||||
|
||||
|
||||
```diff
|
||||
<?php
|
||||
abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
{
|
||||
// …
|
||||
|
||||
protected function buildCollectionCacheKey(
|
||||
AssociationMapping $association,
|
||||
array $ownerId,
|
||||
+ string $filterHash
|
||||
): CollectionCacheKey {
|
||||
// …
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Require implementation of `OutputWalker`, remove `SqlWalker::getExecutor()`
|
||||
|
||||
The `SqlWalker::getExecutor()` method is removed. Output walkers should
|
||||
implement the `\Doctrine\ORM\Query\OutputWalker` interface and create
|
||||
`Doctrine\ORM\Query\Exec\SqlFinalizer` instances.
|
||||
|
||||
## Remove `DatabaseDriver`
|
||||
|
||||
The class `Doctrine\ORM\Mapping\Driver\DatabaseDriver` is removed.
|
||||
|
||||
## Remove the `NotSupported` exception
|
||||
|
||||
The class `Doctrine\ORM\Exception\NotSupported` has been removed without replacement.
|
||||
|
||||
## Remove remaining `Serializable` implementation
|
||||
|
||||
`SequenceGenerator` does not implement the `Serializable` interface anymore.
|
||||
|
||||
The following methods have been removed:
|
||||
|
||||
* `SequenceGenerator::serialize()`
|
||||
* `SequenceGenerator::unserialize()`
|
||||
|
||||
## Remove `orm:schema-tool:update` option `--complete`
|
||||
|
||||
That option was a no-op.
|
||||
|
||||
## Remove `Doctrine\ORM\Mapping\ReflectionEnumProperty`
|
||||
|
||||
This class has been removed.
|
||||
Instead, use `Doctrine\Persistence\Reflection\EnumReflectionProperty` from
|
||||
`doctrine/persistence`.
|
||||
|
||||
## Forbid passing null to `ClassMetadata::fullyQualifiedClassName()`
|
||||
|
||||
Passing `null` to `Doctrine\ORM\ClassMetadata::fullyQualifiedClassName()` is
|
||||
no longer possible.
|
||||
|
||||
## Remove array access
|
||||
|
||||
Using array access on instances of the following classes is no longer possible:
|
||||
|
||||
- `Doctrine\ORM\Mapping\DiscriminatorColumnMapping`
|
||||
- `Doctrine\ORM\Mapping\EmbedClassMapping`
|
||||
- `Doctrine\ORM\Mapping\FieldMapping`
|
||||
- `Doctrine\ORM\Mapping\JoinColumnMapping`
|
||||
- `Doctrine\ORM\Mapping\JoinTableMapping`
|
||||
|
||||
## Remove properties `$indexes` and `$uniqueConstraints` from `Doctrine\ORM\Mapping\Table`
|
||||
|
||||
The properties `$indexes` and `$uniqueConstraints` have been removed since they had no effect at all.
|
||||
The preferred way of defining indices and unique constraints is by
|
||||
using the `\Doctrine\ORM\Mapping\UniqueConstraint` and `\Doctrine\ORM\Mapping\Index` attributes.
|
||||
|
||||
# Upgrade to 3.x General Notes
|
||||
|
||||
We recommend you upgrade to DBAL 3 first before upgrading to ORM 3. See
|
||||
the DBAL upgrade docs: https://github.com/doctrine/dbal/blob/3.10.x/UPGRADE.md
|
||||
|
||||
Rather than doing several major upgrades at once, we recommend you do the following:
|
||||
|
||||
- upgrade to DBAL 3
|
||||
- deploy and monitor
|
||||
- upgrade to ORM 3
|
||||
- deploy and monitor
|
||||
- upgrade to DBAL 4
|
||||
- deploy and monitor
|
||||
|
||||
If you are using Symfony, the recommended minimal Doctrine Bundle version is 2.15
|
||||
to run with ORM 3.
|
||||
|
||||
At this point, we recommend upgrading to PHP 8.4 first and then directly from
|
||||
ORM 2.19 to 3.5 and up so that you can skip the lazy ghost proxy generation
|
||||
and directly start using native lazy objects.
|
||||
>>>>>>> origin/3.6.x
|
||||
|
||||
# Upgrade to 3.7
|
||||
|
||||
## Conditional breaking changes
|
||||
|
||||
3.7 adds support for `doctrine/collections` 3. If you upgrade to that version
|
||||
of `doctrine/collections`, there are breaking changes in `doctrine/orm` as well,
|
||||
because of cross-package inheritance and type declarations.
|
||||
|
||||
Most notably, `Doctrine\ORM\PersistentCollection::add` no longer returns a boolean:
|
||||
|
||||
```diff
|
||||
- public function add(mixed $value): bool
|
||||
+ public function add(mixed $value): void
|
||||
```
|
||||
|
||||
That method always returned `true`, so you can safely stop using the return
|
||||
value before upgrading.
|
||||
|
||||
Also, if you extend `Doctrine\ORM\Persisters\SqlValueVisitor`, you need to
|
||||
ensure the following methods have a return type in your subclasses:
|
||||
|
||||
- `walkComparison()`
|
||||
- `walkCompositeExpression()`
|
||||
- `walkValue()`
|
||||
|
||||
## Deprecate `EventManager` return type in `EntityManager` methods
|
||||
|
||||
The return type of the following methods has been changed from
|
||||
`Doctrine\Common\EventManager` to `Doctrine\Common\EventManagerInterface`:
|
||||
|
||||
- `Doctrine\ORM\Decorator\EntityManagerDecorator::getEventManager()`
|
||||
- `Doctrine\ORM\EntityManager::getEventManager()`
|
||||
- `Doctrine\ORM\EntityManagerInterface::getEventManager()`
|
||||
|
||||
All three methods continue to return an instance of `EventManager`, however
|
||||
relying on that is deprecated and will no longer be the guaranteed in 4.0.
|
||||
|
||||
# Upgrade to 3.6
|
||||
|
||||
## Deprecate using string expression for default values in mappings
|
||||
|
||||
Using a string expression for default values in field mappings is deprecated.
|
||||
Use `Doctrine\DBAL\Schema\DefaultExpression` instances instead.
|
||||
|
||||
Here is how to address this deprecation when mapping entities using PHP attributes:
|
||||
|
||||
```diff
|
||||
use DateTime;
|
||||
+use Doctrine\DBAL\Schema\DefaultExpression\CurrentDate;
|
||||
+use Doctrine\DBAL\Schema\DefaultExpression\CurrentTime;
|
||||
+use Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity]
|
||||
final class TimeEntity
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column]
|
||||
public int $id;
|
||||
|
||||
- #[ORM\Column(options: ['default' => 'CURRENT_TIMESTAMP'], insertable: false, updatable: false)]
|
||||
+ #[ORM\Column(options: ['default' => new CurrentTimestamp()], insertable: false, updatable: false)]
|
||||
public DateTime $createdAt;
|
||||
|
||||
- #[ORM\Column(options: ['default' => 'CURRENT_TIME'], insertable: false, updatable: false)]
|
||||
+ #[ORM\Column(options: ['default' => new CurrentTime()], insertable: false, updatable: false)]
|
||||
public DateTime $createdTime;
|
||||
|
||||
- #[ORM\Column(options: ['default' => 'CURRENT_DATE'], insertable: false, updatable: false)]
|
||||
+ #[ORM\Column(options: ['default' => new CurrentDate()], insertable: false, updatable: false)]
|
||||
public DateTime $createdDate;
|
||||
}
|
||||
```
|
||||
|
||||
Here is how to do the same when mapping entities using XML:
|
||||
|
||||
```diff
|
||||
<?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\ORM\Functional\XmlTimeEntity">
|
||||
<id name="id" type="integer" column="id">
|
||||
<generator strategy="AUTO"/>
|
||||
</id>
|
||||
|
||||
<field name="createdAt" type="datetime" insertable="false" updatable="false">
|
||||
<options>
|
||||
- <option name="default">CURRENT_TIMESTAMP</option>
|
||||
+ <option name="default">
|
||||
+ <object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp"/>
|
||||
+ </option>
|
||||
</options>
|
||||
</field>
|
||||
|
||||
<field name="createdAtImmutable" type="datetime_immutable" insertable="false" updatable="false">
|
||||
<options>
|
||||
- <option name="default">CURRENT_TIMESTAMP</option>
|
||||
+ <option name="default">
|
||||
+ <object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp"/>
|
||||
+ </option>
|
||||
</options>
|
||||
</field>
|
||||
|
||||
<field name="createdTime" type="time" insertable="false" updatable="false">
|
||||
<options>
|
||||
- <option name="default">CURRENT_TIME</option>
|
||||
+ <option name="default">
|
||||
+ <object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentTime"/>
|
||||
+ </option>
|
||||
</options>
|
||||
</field>
|
||||
<field name="createdDate" type="date" insertable="false" updatable="false">
|
||||
<options>
|
||||
- <option name="default">CURRENT_DATE</option>
|
||||
+ <option name="default">
|
||||
+ <object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentDate"/>
|
||||
+ </option>
|
||||
</options>
|
||||
</field>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
```
|
||||
|
||||
|
||||
## Deprecate `FieldMapping::$default`
|
||||
|
||||
The `default` property of `Doctrine\ORM\Mapping\FieldMapping` is deprecated and
|
||||
will be removed in 4.0. Instead, use `FieldMapping::$options['default']`.
|
||||
|
||||
## Deprecate specifying `nullable` on columns that end up being used in a primary key
|
||||
|
||||
Specifying `nullable` on join columns that are part of a primary key is
|
||||
deprecated and will be an error in 4.0.
|
||||
|
||||
This can happen when using a join column mapping together with an id mapping,
|
||||
or when using a join column mapping or an inverse join column mapping on a
|
||||
many-to-many relationship.
|
||||
|
||||
```diff
|
||||
class User
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int $id;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\ManyToOne(targetEntity: Family::class, inversedBy: 'users')]
|
||||
- #[ORM\JoinColumn(name: 'family_id', referencedColumnName: 'id', nullable: true)]
|
||||
+ #[ORM\JoinColumn(name: 'family_id', referencedColumnName: 'id')]
|
||||
private ?Family $family;
|
||||
|
||||
#[ORM\ManyToMany(targetEntity: Group::class)]
|
||||
#[ORM\JoinTable(name: 'user_group')]
|
||||
- #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: true)]
|
||||
- #[ORM\InverseJoinColumn(name: 'group_id', referencedColumnName: 'id', nullable: true)]
|
||||
+ #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id')]
|
||||
+ #[ORM\InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')]
|
||||
private Collection $groups;
|
||||
}
|
||||
```
|
||||
|
||||
## Deprecate `Doctrine\ORM\QueryBuilder::add('join', ...)` with a list of join parts
|
||||
|
||||
Using `Doctrine\ORM\QueryBuilder::add('join', ...)` with a list of join parts
|
||||
is deprecated in favor of using an associative array of join parts with the
|
||||
root alias as key.
|
||||
|
||||
## Deprecate using the `WITH` keyword for arbitrary DQL joins
|
||||
|
||||
Using the `WITH` keyword to specify the condition for an arbitrary DQL join is
|
||||
deprecated in favor of using the `ON` keyword (similar to the SQL syntax for
|
||||
joins).
|
||||
The `WITH` keyword is now meant to be used only for filtering conditions in
|
||||
association joins.
|
||||
|
||||
# Upgrade to 3.5
|
||||
|
||||
See the General notes to upgrading to 3.x versions above.
|
||||
|
||||
## Deprecate not using native lazy objects on PHP 8.4+
|
||||
|
||||
Having native lazy objects disabled on PHP 8.4+ is deprecated and will not be
|
||||
possible in 4.0.
|
||||
|
||||
You can enable them through configuration:
|
||||
|
||||
```php
|
||||
$config->enableNativeLazyObjects(true);
|
||||
```
|
||||
|
||||
As a consequence, methods, parameters and commands related to userland lazy
|
||||
objects have been deprecated on PHP 8.4+:
|
||||
|
||||
- `Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand`
|
||||
- `Doctrine\ORM\Configuration::getAutoGenerateProxyClasses()`
|
||||
- `Doctrine\ORM\Configuration::getProxyDir()`
|
||||
- `Doctrine\ORM\Configuration::getProxyNamespace()`
|
||||
- `Doctrine\ORM\Configuration::setAutoGenerateProxyClasses()`
|
||||
- `Doctrine\ORM\Configuration::setProxyDir()`
|
||||
- `Doctrine\ORM\Configuration::setProxyNamespace()`
|
||||
- Passing more than one argument to `Doctrine\ORM\Proxy\ProxyFactory::__construct()`
|
||||
|
||||
Additionally, some methods of ORMSetup have been deprecated in favor of a new
|
||||
counterpart.
|
||||
|
||||
- `Doctrine\ORM\ORMSetup::createAttributeMetadataConfiguration()` is deprecated in favor of
|
||||
`Doctrine\ORM\ORMSetup::createAttributeMetadataConfig()`
|
||||
- `Doctrine\ORM\ORMSetup::createXMLMetadataConfiguration()` is deprecated in favor of
|
||||
`Doctrine\ORM\ORMSetup::createXMLMetadataConfig()`
|
||||
- `Doctrine\ORM\ORMSetup::createConfiguration()` is deprecated in favor of
|
||||
`Doctrine\ORM\ORMSetup::createConfig()`
|
||||
|
||||
## Deprecate methods for configuring no longer configurable features
|
||||
|
||||
Since 3.0, lazy ghosts are enabled unconditionally, and so is rejecting ID
|
||||
collisions in the identity map.
|
||||
|
||||
As a consequence, the following methods are deprecated and will be removed in 4.0:
|
||||
* `Doctrine\ORM\Configuration::setLazyGhostObjectEnabled()`
|
||||
* `Doctrine\ORM\Configuration::isLazyGhostObjectEnabled()`
|
||||
* `Doctrine\ORM\Configuration::setRejectIdCollisionInIdentityMap()`
|
||||
* `Doctrine\ORM\Configuration::isRejectIdCollisionInIdentityMapEnabled()`
|
||||
|
||||
# Upgrade to 3.4.1
|
||||
|
||||
## BC BREAK: You can no longer use the `.*` notation to get all fields of an entity in a DTO
|
||||
@@ -7,6 +403,8 @@ decide to remove it before it is used too widely.
|
||||
|
||||
# Upgrade to 3.4
|
||||
|
||||
See the General notes to upgrading to 3.x versions above.
|
||||
|
||||
## Discriminator Map class duplicates
|
||||
|
||||
Using the same class several times in a discriminator map is deprecated.
|
||||
@@ -23,8 +421,12 @@ that implements `ArrayAccess`.
|
||||
Use the new `Doctrine\ORM\Mapping\PropertyAccessors\PropertyAccessor` API and access
|
||||
through `Doctrine\ORM\Mapping\ClassMetadata::$propertyAccessors` instead.
|
||||
|
||||
Companion accessor methods are deprecated as well.
|
||||
|
||||
# Upgrade to 3.3
|
||||
|
||||
See the General notes to upgrading to 3.x versions above.
|
||||
|
||||
## Deprecate `DatabaseDriver`
|
||||
|
||||
The class `Doctrine\ORM\Mapping\Driver\DatabaseDriver` is deprecated without replacement.
|
||||
@@ -41,6 +443,8 @@ method. Details can be found at https://github.com/doctrine/orm/pull/11188.
|
||||
|
||||
# Upgrade to 3.2
|
||||
|
||||
See the General notes to upgrading to 3.x versions above.
|
||||
|
||||
## Deprecate the `NotSupported` exception
|
||||
|
||||
The class `Doctrine\ORM\Exception\NotSupported` is deprecated without replacement.
|
||||
@@ -67,6 +471,8 @@ using the `\Doctrine\ORM\Mapping\UniqueConstraint` and `\Doctrine\ORM\Mapping\In
|
||||
|
||||
# Upgrade to 3.1
|
||||
|
||||
See the General notes to upgrading to 3.x versions above.
|
||||
|
||||
## Deprecate `Doctrine\ORM\Mapping\ReflectionEnumProperty`
|
||||
|
||||
This class is deprecated and will be removed in 4.0.
|
||||
@@ -90,6 +496,8 @@ Using array access on instances of the following classes is deprecated:
|
||||
|
||||
# Upgrade to 3.0
|
||||
|
||||
See the General notes to upgrading to 3.x versions above.
|
||||
|
||||
## BC BREAK: Calling `ClassMetadata::getAssociationMappedByTargetField()` with the owning side of an association now throws an exception
|
||||
|
||||
Previously, calling
|
||||
@@ -115,6 +523,9 @@ so `$targetEntity` is a first argument now. This change affects only non-named a
|
||||
When using the `AUTO` strategy to let Doctrine determine the identity generation mechanism for
|
||||
an entity, and when using `doctrine/dbal` 4, PostgreSQL now uses `IDENTITY`
|
||||
instead of `SEQUENCE` or `SERIAL`.
|
||||
|
||||
There are three ways to handle this change.
|
||||
|
||||
* If you want to upgrade your existing tables to identity columns, you will need to follow [migration to identity columns on PostgreSQL](https://www.doctrine-project.org/projects/doctrine-dbal/en/4.0/how-to/postgresql-identity-migration.html)
|
||||
* If you want to keep using SQL sequences, you need to configure the ORM this way:
|
||||
```php
|
||||
@@ -127,6 +538,27 @@ $configuration->setIdentityGenerationPreferences([
|
||||
PostgreSQLPlatform::CLASS => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
|
||||
]);
|
||||
```
|
||||
* You can change individual entities to use the `SEQUENCE` strategy instead of `AUTO`:
|
||||
```php
|
||||
|
||||
diff --git a/src/Entity/Example.php b/src/Entity/Example.php
|
||||
index 28be8df378..3b7d61bda6 100644
|
||||
--- a/src/Entity/Example.php
|
||||
+++ b/src/Entity/Example.php
|
||||
@@ -38,7 +38,7 @@ class Example
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
- #[ORM\GeneratedValue(strategy: 'AUTO')]
|
||||
+ #[ORM\GeneratedValue(strategy: 'SEQUENCE')]
|
||||
private int $id;
|
||||
|
||||
#[Assert\Length(max: 255)]
|
||||
```
|
||||
The later two options require a small database migration that will remove the default
|
||||
expression fetching the next value from the sequence. It's not strictly necessary to
|
||||
do this migration because the code will work anyway. A benefit of this approach is
|
||||
that you can just make and roll out the code changes first and then migrate the database later.
|
||||
|
||||
## BC BREAK: Throw exceptions when using illegal attributes on Embeddable
|
||||
|
||||
@@ -2046,7 +2478,7 @@ from 2.0 have to configure the annotation driver if they don't use `Configuratio
|
||||
|
||||
## Scalar mappings can now be omitted from DQL result
|
||||
|
||||
You are now allowed to mark scalar SELECT expressions as HIDDEN an they are not hydrated anymore.
|
||||
You are now allowed to mark scalar SELECT expressions as HIDDEN and they are not hydrated anymore.
|
||||
Example:
|
||||
|
||||
SELECT u, SUM(a.id) AS HIDDEN numArticles FROM User u LEFT JOIN u.Articles a ORDER BY numArticles DESC HAVING numArticles > 10
|
||||
|
||||
124
composer.json
124
composer.json
@@ -1,17 +1,77 @@
|
||||
{
|
||||
"name": "doctrine/orm",
|
||||
"type": "library",
|
||||
"description": "Object-Relational-Mapper for PHP",
|
||||
"keywords": ["orm", "database"],
|
||||
"homepage": "https://www.doctrine-project.org/projects/orm.html",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
|
||||
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
|
||||
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
|
||||
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
|
||||
{"name": "Marco Pivetta", "email": "ocramius@gmail.com"}
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"orm",
|
||||
"database"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com"
|
||||
}
|
||||
],
|
||||
"homepage": "https://www.doctrine-project.org/projects/orm.html",
|
||||
"require": {
|
||||
"php": "^8.4",
|
||||
"ext-ctype": "*",
|
||||
"composer-runtime-api": "^2",
|
||||
"doctrine/collections": "^3",
|
||||
"doctrine/dbal": "^4.2.1",
|
||||
"doctrine/deprecations": "^1.1",
|
||||
"doctrine/event-manager": "^2.1.1",
|
||||
"doctrine/inflector": "^1.4 || ^2.0",
|
||||
"doctrine/instantiator": "^1.3 || ^2",
|
||||
"doctrine/lexer": "^3",
|
||||
"doctrine/persistence": "^4",
|
||||
"psr/cache": "^1 || ^2 || ^3",
|
||||
"symfony/console": "^5.4 || ^6.0 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^14.0",
|
||||
"phpbench/phpbench": "^1.0",
|
||||
"phpstan/extension-installer": "^1.4",
|
||||
"phpstan/phpstan": "2.1.23",
|
||||
"phpstan/phpstan-deprecation-rules": "^2",
|
||||
"phpunit/phpunit": "^11.5.42",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"symfony/cache": "^5.4 || ^6.2 || ^7.0 || ^8.0",
|
||||
"symfony/var-exporter": "^6.3.9 || ^7.0 || ^8.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Provides support for XSD validation for XML mapping files",
|
||||
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\ORM\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Performance\\": "tests/Performance",
|
||||
"Doctrine\\StaticAnalysis\\": "tests/StaticAnalysis",
|
||||
"Doctrine\\Tests\\": "tests/Tests"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
@@ -20,49 +80,7 @@
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"composer-runtime-api": "^2",
|
||||
"ext-ctype": "*",
|
||||
"doctrine/collections": "^2.2",
|
||||
"doctrine/dbal": "^3.8.2 || ^4",
|
||||
"doctrine/deprecations": "^0.5.3 || ^1",
|
||||
"doctrine/event-manager": "^1.2 || ^2",
|
||||
"doctrine/inflector": "^1.4 || ^2.0",
|
||||
"doctrine/instantiator": "^1.3 || ^2",
|
||||
"doctrine/lexer": "^3",
|
||||
"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": "^13.0",
|
||||
"phpbench/phpbench": "^1.0",
|
||||
"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.12.0",
|
||||
"symfony/cache": "^5.4 || ^6.2 || ^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Provides support for XSD validation for XML mapping files",
|
||||
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Doctrine\\ORM\\": "src" }
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Tests\\": "tests/Tests",
|
||||
"Doctrine\\StaticAnalysis\\": "tests/StaticAnalysis",
|
||||
"Doctrine\\Performance\\": "tests/Performance"
|
||||
}
|
||||
},
|
||||
"archive": {
|
||||
"exclude": ["!vendor", "tests", "*phpunit.xml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp"]
|
||||
"scripts": {
|
||||
"docs": "composer --working-dir docs update && ./docs/vendor/bin/build-docs.sh @additional_args"
|
||||
}
|
||||
}
|
||||
|
||||
2
docs/.gitignore
vendored
2
docs/.gitignore
vendored
@@ -1,3 +1,3 @@
|
||||
composer.lock
|
||||
vendor/
|
||||
build/
|
||||
output/
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# 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."
|
||||
@@ -4,19 +4,15 @@ The documentation is written in [ReStructured Text](https://docutils.sourceforge
|
||||
|
||||
## How to Generate:
|
||||
|
||||
In the `docs/` folder, run
|
||||
In the project root, run
|
||||
|
||||
composer update
|
||||
composer docs
|
||||
|
||||
Then compile the documentation with:
|
||||
|
||||
make html
|
||||
|
||||
This will generate the documentation into the `build` subdirectory.
|
||||
This will generate the documentation into the `docs/output` subdirectory.
|
||||
|
||||
To browse the documentation, you need to run a webserver:
|
||||
|
||||
cd build/html
|
||||
cd docs/output
|
||||
php -S localhost:8000
|
||||
|
||||
Now the documentation is available at [http://localhost:8000](http://localhost:8000).
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
"description": "Documentation for the Object-Relational Mapper\"",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"phpdocumentor/guides-cli": "1.7.1",
|
||||
"phpdocumentor/filesystem": "1.7.1"
|
||||
"require-dev": {
|
||||
"doctrine/docs-builder": "^1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ Now this is all awfully technical, so let me come to some use-cases
|
||||
fast to keep you motivated. Using walker implementation you can for
|
||||
example:
|
||||
|
||||
|
||||
- Modify the Output walker to get the raw SQL via ``Query->getSQL()``
|
||||
with interpolated parameters.
|
||||
- Modify the AST to generate a Count Query to be used with a
|
||||
paginator for any given DQL query.
|
||||
- Modify the Output Walker to generate vendor-specific SQL
|
||||
@@ -50,7 +51,7 @@ example:
|
||||
- Modify the Output walker to pretty print the SQL for debugging
|
||||
purposes.
|
||||
|
||||
In this cookbook-entry I will show examples of the first two
|
||||
In this cookbook-entry I will show examples of the first three
|
||||
points. There are probably much more use-cases.
|
||||
|
||||
Generic count query for pagination
|
||||
@@ -101,8 +102,16 @@ The ``Paginate::count(Query $query)`` looks like:
|
||||
{
|
||||
static public function count(Query $query)
|
||||
{
|
||||
/** @var Query $countQuery */
|
||||
$countQuery = clone $query;
|
||||
/*
|
||||
To avoid changing the $query passed into the method and to make sure a possibly existing
|
||||
ResultSetMapping is discarded, we create a new query object any copy relevant data over.
|
||||
*/
|
||||
$countQuery = new Query($query->getEntityManager());
|
||||
$countQuery->setDQL($query->getDQL());
|
||||
$countQuery->setParameters(clone $query->getParameters());
|
||||
foreach ($query->getHints() as $name => $value) {
|
||||
$countQuery->setHint($name, $value);
|
||||
}
|
||||
|
||||
$countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('DoctrineExtensions\Paginate\CountSqlWalker'));
|
||||
$countQuery->setFirstResult(null)->setMaxResults(null);
|
||||
@@ -111,7 +120,7 @@ The ``Paginate::count(Query $query)`` looks like:
|
||||
}
|
||||
}
|
||||
|
||||
It clones the query, resets the limit clause first and max results
|
||||
This resets the limit clause first and max results
|
||||
and registers the ``CountSqlWalker`` custom tree walker which
|
||||
will modify the AST to execute a count query. The walkers
|
||||
implementation is:
|
||||
@@ -215,3 +224,39 @@ huge benefits with using vendor specific features. This would still
|
||||
allow you write DQL queries instead of NativeQueries to make use of
|
||||
vendor specific features.
|
||||
|
||||
Modifying the Output Walker to get the raw SQL with interpolated parameters
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Sometimes we may want to log or trace the raw SQL being generated from its DQL
|
||||
for profiling slow queries afterwards or audit queries that changed many rows
|
||||
``$query->getSQL()`` will give us the prepared statement being passed to database
|
||||
with all values of SQL parameters being replaced by positional ``?`` or named ``:name``
|
||||
as parameters are interpolated into prepared statements by the database while executing the SQL.
|
||||
``$query->getParameters()`` will give us details about SQL parameters that we've provided.
|
||||
So we can create an output walker to interpolate all SQL parameters that will be
|
||||
passed into prepared statement in PHP before database handle them internally:
|
||||
|
||||
.. literalinclude:: dql-custom-walkers/InterpolateParametersSQLOutputWalker.php
|
||||
:language: php
|
||||
|
||||
Then you may get the raw SQL with this output walker:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query
|
||||
->where('t.int IN (:ints)')->setParameter(':ints', [1, 2])
|
||||
->orWhere('t.string IN (?0)')->setParameter(0, ['3', '4'])
|
||||
->orWhere("t.bool = ?1")->setParameter('?1', true)
|
||||
->orWhere("t.string = :string")->setParameter(':string', 'ABC')
|
||||
->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, InterpolateParametersSQLOutputWalker::class)
|
||||
->getSQL();
|
||||
|
||||
The where clause of the returned SQL should be like:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
WHERE t0_.int IN (1, 2)
|
||||
OR t0_.string IN ('3', '4')
|
||||
OR t0_.bool = 1
|
||||
OR t0_.string = 'ABC'
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
use Doctrine\DBAL\ArrayParameterType;
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use Doctrine\DBAL\Types\BooleanType;
|
||||
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\Query\AST;
|
||||
use Doctrine\ORM\Query\SqlOutputWalker;
|
||||
|
||||
class InterpolateParametersSQLOutputWalker extends SqlOutputWalker
|
||||
{
|
||||
/** {@inheritdoc} */
|
||||
public function walkInputParameter(AST\InputParameter $inputParam): string
|
||||
{
|
||||
$parameter = $this->getQuery()->getParameter($inputParam->name);
|
||||
if ($parameter === null) {
|
||||
return '?';
|
||||
}
|
||||
|
||||
$value = $parameter->getValue();
|
||||
/** @var ParameterType|ArrayParameterType|int|string $typeName */
|
||||
/** @see \Doctrine\ORM\Query\ParameterTypeInferer::inferType() */
|
||||
$typeName = $parameter->getType();
|
||||
$platform = $this->getConnection()->getDatabasePlatform();
|
||||
$processParameterType = static fn(ParameterType $type) => static fn($value): string =>
|
||||
(match ($type) { /** @see Type::getBindingType() */
|
||||
ParameterType::NULL => 'NULL',
|
||||
ParameterType::INTEGER => $value,
|
||||
ParameterType::BOOLEAN => (new BooleanType())->convertToDatabaseValue($value, $platform),
|
||||
ParameterType::STRING, ParameterType::ASCII => $platform->quoteStringLiteral($value),
|
||||
default => throw new ValueNotConvertible($value, $type->name)
|
||||
});
|
||||
|
||||
if (is_string($typeName) && Type::hasType($typeName)) {
|
||||
return Type::getType($typeName)->convertToDatabaseValue($value, $platform);
|
||||
}
|
||||
if ($typeName instanceof ParameterType) {
|
||||
return $processParameterType($typeName)($value);
|
||||
}
|
||||
if ($typeName instanceof ArrayParameterType && is_array($value)) {
|
||||
$type = ArrayParameterType::toElementParameterType($typeName);
|
||||
return implode(', ', array_map($processParameterType($type), $value));
|
||||
}
|
||||
|
||||
throw new ValueNotConvertible($value, $typeName);
|
||||
}
|
||||
}
|
||||
@@ -46,17 +46,18 @@ entities:
|
||||
#[Entity]
|
||||
class Article
|
||||
{
|
||||
const STATUS_VISIBLE = 'visible';
|
||||
const STATUS_INVISIBLE = 'invisible';
|
||||
public const STATUS_VISIBLE = 'visible';
|
||||
public const STATUS_INVISIBLE = 'invisible';
|
||||
|
||||
#[Column(type: "string")]
|
||||
private $status;
|
||||
|
||||
public function setStatus($status)
|
||||
public function setStatus(string $status): void
|
||||
{
|
||||
if (!in_array($status, array(self::STATUS_VISIBLE, self::STATUS_INVISIBLE))) {
|
||||
if (!in_array($status, [self::STATUS_VISIBLE, self::STATUS_INVISIBLE], true)) {
|
||||
throw new \InvalidArgumentException("Invalid status");
|
||||
}
|
||||
|
||||
$this->status = $status;
|
||||
}
|
||||
}
|
||||
@@ -92,37 +93,33 @@ For example for the previous enum type:
|
||||
|
||||
class EnumVisibilityType extends Type
|
||||
{
|
||||
const ENUM_VISIBILITY = 'enumvisibility';
|
||||
const STATUS_VISIBLE = 'visible';
|
||||
const STATUS_INVISIBLE = 'invisible';
|
||||
private const ENUM_VISIBILITY = 'enumvisibility';
|
||||
private const STATUS_VISIBLE = 'visible';
|
||||
private const STATUS_INVISIBLE = 'invisible';
|
||||
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
|
||||
{
|
||||
return "ENUM('visible', 'invisible')";
|
||||
}
|
||||
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): string
|
||||
{
|
||||
if (!in_array($value, array(self::STATUS_VISIBLE, self::STATUS_INVISIBLE))) {
|
||||
if (!in_array($value, [self::STATUS_VISIBLE, self::STATUS_INVISIBLE], true)) {
|
||||
throw new \InvalidArgumentException("Invalid status");
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
public function getName(): string
|
||||
{
|
||||
return self::ENUM_VISIBILITY;
|
||||
}
|
||||
|
||||
public function requiresSQLCommentHint(AbstractPlatform $platform)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
You can register this type with ``Type::addType('enumvisibility', 'MyProject\DBAL\EnumVisibilityType');``.
|
||||
@@ -151,37 +148,33 @@ You can generalize this approach easily to create a base class for enums:
|
||||
abstract class EnumType extends Type
|
||||
{
|
||||
protected $name;
|
||||
protected $values = array();
|
||||
protected $values = [];
|
||||
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
|
||||
{
|
||||
$values = array_map(function($val) { return "'".$val."'"; }, $this->values);
|
||||
$values = array_map(fn($val) => "'".$val."'", $this->values);
|
||||
|
||||
return "ENUM(".implode(", ", $values).")";
|
||||
}
|
||||
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): mixed
|
||||
{
|
||||
if (!in_array($value, $this->values)) {
|
||||
if (!in_array($value, $this->values, true)) {
|
||||
throw new \InvalidArgumentException("Invalid '".$this->name."' value.");
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function requiresSQLCommentHint(AbstractPlatform $platform)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
With this base class you can define an enum as easily as:
|
||||
@@ -194,5 +187,5 @@ With this base class you can define an enum as easily as:
|
||||
class EnumVisibilityType extends EnumType
|
||||
{
|
||||
protected $name = 'enumvisibility';
|
||||
protected $values = array('visible', 'invisible');
|
||||
protected $values = ['visible', 'invisible'];
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ If this documentation is not helping to answer questions you have about
|
||||
Doctrine ORM don't panic. You can get help from different sources:
|
||||
|
||||
- There is a :doc:`FAQ <reference/faq>` with answers to frequent questions.
|
||||
- The `Doctrine Mailing List <https://groups.google.com/group/doctrine-user>`_
|
||||
- Slack chat room `#orm <https://www.doctrine-project.org/slack>`_
|
||||
- Report a bug on `GitHub <https://github.com/doctrine/orm/issues>`_.
|
||||
- On `StackOverflow <https://stackoverflow.com/questions/tagged/doctrine-orm>`_
|
||||
|
||||
@@ -29,22 +29,11 @@ steps of configuration.
|
||||
|
||||
$config = new Configuration;
|
||||
$config->setMetadataCache($metadataCache);
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']);
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
$config->setQueryCache($queryCache);
|
||||
|
||||
if (PHP_VERSION_ID > 80400) {
|
||||
$config->enableNativeLazyObjects(true);
|
||||
} else {
|
||||
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
|
||||
$config->setProxyNamespace('MyProject\Proxies');
|
||||
|
||||
if ($applicationMode === "development") {
|
||||
$config->setAutoGenerateProxyClasses(true);
|
||||
} else {
|
||||
$config->setAutoGenerateProxyClasses(false);
|
||||
}
|
||||
}
|
||||
$config->enableNativeLazyObjects(true);
|
||||
|
||||
$connection = DriverManager::getConnection([
|
||||
'driver' => 'pdo_sqlite',
|
||||
@@ -76,53 +65,6 @@ Configuration Options
|
||||
The following sections describe all the configuration options
|
||||
available on a ``Doctrine\ORM\Configuration`` instance.
|
||||
|
||||
Native Lazy Objects (**OPTIONAL**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
With PHP 8.4 we recommend that you use native lazy objects instead of
|
||||
the code generation approach using the ``symfony/var-exporter`` Ghost trait.
|
||||
|
||||
With Doctrine 4, the minimal requirement will become PHP 8.4 and native lazy objects
|
||||
will become the only approach to lazy loading.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$config->enableNativeLazyObjects(true);
|
||||
|
||||
Proxy Directory
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Required except if you use native lazy objects with PHP 8.4.
|
||||
This setting will be removed in the future.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$config->setProxyDir($dir);
|
||||
$config->getProxyDir();
|
||||
|
||||
Gets or sets the directory where Doctrine generates any proxy
|
||||
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 except if you use native lazy objects with PHP 8.4.
|
||||
This setting will be removed in the future.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$config->setProxyNamespace($namespace);
|
||||
$config->getProxyNamespace();
|
||||
|
||||
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**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -154,15 +96,59 @@ The attribute driver can be injected in the ``Doctrine\ORM\Configuration``:
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
|
||||
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']);
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
|
||||
The path information to the entities is required for the attribute
|
||||
driver, because otherwise mass-operations on all entities through
|
||||
the console could not work correctly. All of metadata drivers
|
||||
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.
|
||||
the console could not work correctly. Metadata drivers can accept either
|
||||
a single directory as a string or an array of directories.
|
||||
|
||||
AttributeDriver also accepts ``Doctrine\Persistence\Mapping\Driver\ClassLocator``,
|
||||
allowing one to customize file discovery logic. You may choose to use Symfony Finder, or
|
||||
utilize directory scan with ``FileClassLocator::createFromDirectories()``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
|
||||
use Doctrine\Persistence\Mapping\Driver\FileClassLocator;
|
||||
|
||||
$paths = ['/path/to/lib/MyProject/Entities'];
|
||||
$classLocator = FileClassLocator::createFromDirectories($paths);
|
||||
|
||||
$driverImpl = new AttributeDriver($classLocator);
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
|
||||
With this feature, you're empowered to provide a fine-grained iterator of only necessary
|
||||
files to the Driver. For example, if you are using Vertical Slice architecture, you can
|
||||
exclude ``*Test.php``, ``*Controller.php``, ``*Service.php``, etc.:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
$finder = new Finder()->files()->in($paths)
|
||||
->name('*.php')
|
||||
->notName(['*Test.php', '*Controller.php', '*Service.php']);
|
||||
|
||||
$classLocator = new FileClassLocator($finder);
|
||||
|
||||
If you know the list of class names you want to track, use
|
||||
``Doctrine\Persistence\Mapping\Driver\ClassNames``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\Persistence\Mapping\Driver\ClassNames;
|
||||
use App\Entity\{Article, Book};
|
||||
|
||||
$entityClasses = [Article::class, Book::class];
|
||||
$classLocator = new ClassNames($entityClasses);
|
||||
|
||||
$driverImpl = new AttributeDriver($classLocator);
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
|
||||
Metadata Cache (**RECOMMENDED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -222,63 +208,6 @@ 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**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This setting is not required if you use native lazy objects with PHP 8.4
|
||||
and will be removed in the future.
|
||||
|
||||
Proxy classes can either be generated manually through the Doctrine
|
||||
Console or automatically at runtime by Doctrine. The configuration
|
||||
option that controls this behavior is:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$config->setAutoGenerateProxyClasses($mode);
|
||||
|
||||
Possible values for ``$mode`` are:
|
||||
|
||||
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_NEVER``
|
||||
|
||||
Never autogenerate a proxy. You will need to generate the proxies
|
||||
manually, for this use the Doctrine Console like so:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ ./doctrine orm:generate-proxies
|
||||
|
||||
When you do this in a development environment,
|
||||
be aware that you may get class/file not found errors if certain proxies
|
||||
are not yet generated. You may also get failing lazy-loads if new
|
||||
methods were added to the entity class that are not yet in the proxy class.
|
||||
In such a case, simply use the Doctrine Console to (re)generate the
|
||||
proxy classes.
|
||||
|
||||
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_ALWAYS``
|
||||
|
||||
Always generates a new proxy in every request and writes it to disk.
|
||||
|
||||
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS``
|
||||
|
||||
Generate the proxy class when the proxy file does not exist.
|
||||
This strategy causes a file exists call whenever any proxy is
|
||||
used the first time in a request.
|
||||
|
||||
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_EVAL``
|
||||
|
||||
Generate the proxy classes and evaluate them on the fly via eval(),
|
||||
avoiding writing the proxies to disk.
|
||||
This strategy is only sane for development.
|
||||
|
||||
In a production environment, it is highly recommended to use
|
||||
AUTOGENERATE_NEVER to allow for optimal performances. The other
|
||||
options are interesting in development environment.
|
||||
|
||||
``setAutoGenerateProxyClasses`` can accept a boolean
|
||||
value. This is still possible, ``FALSE`` being equivalent to
|
||||
AUTOGENERATE_NEVER and ``TRUE`` to AUTOGENERATE_ALWAYS.
|
||||
|
||||
Development vs Production Configuration
|
||||
---------------------------------------
|
||||
|
||||
@@ -302,7 +231,7 @@ requests.
|
||||
Connection
|
||||
----------
|
||||
|
||||
The ``$connection`` passed as the first argument to he constructor of
|
||||
The ``$connection`` passed as the first argument to the constructor of
|
||||
``EntityManager`` has to be an instance of ``Doctrine\DBAL\Connection``.
|
||||
You can use the factory ``Doctrine\DBAL\DriverManager::getConnection()``
|
||||
to create such a connection. The DBAL configuration is explained in the
|
||||
@@ -394,55 +323,6 @@ transparently initialize itself on first access.
|
||||
This will override the 'fetch' option specified in the mapping for
|
||||
that association, but only for that query.
|
||||
|
||||
|
||||
Generating Proxy classes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In a production environment, it is highly recommended to use
|
||||
``AUTOGENERATE_NEVER`` to allow for optimal performances.
|
||||
However you will be required to generate the proxies manually
|
||||
using the Doctrine Console:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ ./doctrine orm:generate-proxies
|
||||
|
||||
The other options are interesting in development environment:
|
||||
|
||||
- ``AUTOGENERATE_ALWAYS`` will require you to create and configure
|
||||
a proxy directory. Proxies will be generated and written to file
|
||||
on each request, so any modification to your code will be acknowledged.
|
||||
|
||||
- ``AUTOGENERATE_FILE_NOT_EXISTS`` will not overwrite an existing
|
||||
proxy file. If your code changes, you will need to regenerate the
|
||||
proxies manually.
|
||||
|
||||
- ``AUTOGENERATE_EVAL`` will regenerate each proxy on each request,
|
||||
but without writing them to disk.
|
||||
|
||||
Autoloading Proxies
|
||||
-------------------
|
||||
|
||||
When you deserialize proxy objects from the session or any other storage
|
||||
it is necessary to have an autoloading mechanism in place for these classes.
|
||||
For implementation reasons Proxy class names are not PSR-0 compliant. This
|
||||
means that you have to register a special autoloader for these classes:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Proxy\Autoloader;
|
||||
|
||||
$proxyDir = "/path/to/proxies";
|
||||
$proxyNamespace = "MyProxies";
|
||||
|
||||
Autoloader::register($proxyDir, $proxyNamespace);
|
||||
|
||||
If you want to execute additional logic to intercept the proxy file not found
|
||||
state you can pass a closure as the third argument. It will be called with
|
||||
the arguments proxydir, namespace and className when the proxy file could not
|
||||
be found.
|
||||
|
||||
Multiple Metadata Sources
|
||||
-------------------------
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ well.
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Doctrine ORM requires a minimum of PHP 8.1. For greatly improved
|
||||
Doctrine ORM requires a minimum of PHP 8.4. For greatly improved
|
||||
performance it is also recommended that you use APC with PHP.
|
||||
|
||||
Doctrine ORM Packages
|
||||
@@ -79,8 +79,8 @@ Entities
|
||||
An entity is a lightweight, persistent domain object. An entity can
|
||||
be any regular PHP class observing the following restrictions:
|
||||
|
||||
- An entity class must not be final nor read-only but
|
||||
it may contain final methods or read-only properties.
|
||||
- An entity class can be final or read-only. It may contain final
|
||||
methods or read-only properties too.
|
||||
- Any two entity classes in a class hierarchy that inherit
|
||||
directly or indirectly from one another must not have a mapped
|
||||
property with the same name. That is, if B inherits from A then B
|
||||
@@ -167,7 +167,7 @@ recommended, at least not as long as an entity instance still holds
|
||||
references to proxy objects or is still managed by an EntityManager.
|
||||
By default, serializing proxy objects does not initialize them. On
|
||||
unserialization, resulting objects are detached from the entity
|
||||
manager and cannot be initialiazed anymore. You can implement the
|
||||
manager and cannot be initialized anymore. You can implement the
|
||||
``__serialize()`` method if you want to change that behavior, but
|
||||
then you need to ensure that you won't generate large serialized
|
||||
object graphs and take care of circular associations.
|
||||
|
||||
@@ -175,6 +175,10 @@ Optional parameters:
|
||||
- **unique**: Boolean value to determine if the value of the column
|
||||
should be unique across all rows of the underlying entities table.
|
||||
|
||||
- **index**: Boolean value to generate an index for this column.
|
||||
For more advanced usages, take a look at :ref:`#[Index] <attrref_index>`.
|
||||
If not specified, default value is ``false``.
|
||||
|
||||
- **nullable**: Determines if NULL values allowed for this column.
|
||||
If not specified, default value is ``false``.
|
||||
|
||||
@@ -245,6 +249,9 @@ Examples:
|
||||
#[Column(type: "string", length: 32, unique: true, nullable: false)]
|
||||
protected $username;
|
||||
|
||||
#[Column(type: "string", index: true)]
|
||||
protected $firstName;
|
||||
|
||||
#[Column(type: "string", columnDefinition: "CHAR(2) NOT NULL")]
|
||||
protected $country;
|
||||
|
||||
@@ -661,11 +668,6 @@ and in the Context of a :ref:`#[ManyToMany] <attrref_manytomany>`. If this attri
|
||||
are missing they will be computed considering the field's name and the current
|
||||
:doc:`naming strategy <namingstrategy>`.
|
||||
|
||||
The ``#[InverseJoinColumn]`` is the same as ``#[JoinColumn]`` and is used in the context
|
||||
of a ``#[ManyToMany]`` attribute declaration to specifiy the details of the join table's
|
||||
column information used for the join to the inverse entity. This is only required
|
||||
on PHP 8.0, where nested attributes are not yet supported.
|
||||
|
||||
Optional parameters:
|
||||
|
||||
- **name**: Column name that holds the foreign key identifier for
|
||||
|
||||
@@ -182,6 +182,37 @@ Here is a complete list of ``Column``s attributes (all optional):
|
||||
- ``options``: Key-value pairs of options that get passed
|
||||
to the underlying database platform when generating DDL statements.
|
||||
|
||||
Specifying default values
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
While it is possible to specify default values for properties in your
|
||||
PHP class, Doctrine also allows you to specify default values for
|
||||
database columns using the ``default`` key in the ``options`` array of
|
||||
the ``Column`` attribute.
|
||||
|
||||
When using XML, you can specify object instances using the ``<object>``
|
||||
element:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<field name="createdAt" type="datetime" insertable="false" updatable="false">
|
||||
<options>
|
||||
<option name="default">
|
||||
<object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp"/>
|
||||
</option>
|
||||
</options>
|
||||
</field>
|
||||
|
||||
The ``<object>`` element requires a ``class`` attribute specifying the
|
||||
fully qualified class name to instantiate.
|
||||
|
||||
.. configuration-block::
|
||||
.. literalinclude:: basic-mapping/DefaultValues.php
|
||||
:language: attribute
|
||||
|
||||
.. literalinclude:: basic-mapping/default-values.xml
|
||||
:language: xml
|
||||
|
||||
.. _reference-php-mapping-types:
|
||||
|
||||
PHP Types Mapping
|
||||
@@ -389,17 +420,19 @@ Here is the list of possible generation strategies:
|
||||
|
||||
- ``AUTO`` (default): Tells Doctrine to pick the strategy that is
|
||||
preferred by the used database platform. The preferred strategies
|
||||
are ``IDENTITY`` for MySQL, SQLite, MsSQL and SQL Anywhere and, for
|
||||
historical reasons, ``SEQUENCE`` for Oracle and PostgreSQL. This
|
||||
strategy provides full portability.
|
||||
are ``IDENTITY`` for MySQL, SQLite, MsSQL, SQL Anywhere and
|
||||
PostgreSQL (on DBAL 4) and, for historical reasons, ``SEQUENCE``
|
||||
for Oracle and PostgreSQL (on DBAL 3). This strategy provides
|
||||
full portability.
|
||||
- ``IDENTITY``: Tells Doctrine to use special identity columns in
|
||||
the database that generate a value on insertion of a row. This
|
||||
strategy does currently not provide full portability and is
|
||||
supported by the following platforms: MySQL/SQLite/SQL Anywhere
|
||||
(``AUTO_INCREMENT``), MSSQL (``IDENTITY``) and PostgreSQL (``SERIAL``).
|
||||
(``AUTO_INCREMENT``), MSSQL (``IDENTITY``) and PostgreSQL (``SERIAL``
|
||||
on DBAL 3, ``GENERATED BY DEFAULT AS IDENTITY`` on DBAL 4).
|
||||
- ``SEQUENCE``: Tells Doctrine to use a database sequence for ID
|
||||
generation. This strategy does currently not provide full
|
||||
portability. Sequences are supported by Oracle, PostgreSql and
|
||||
portability. Sequences are supported by Oracle, PostgreSQL and
|
||||
SQL Anywhere.
|
||||
- ``NONE``: Tells Doctrine that the identifiers are assigned (and
|
||||
thus generated) by your code. The assignment must take place before
|
||||
|
||||
20
docs/en/reference/basic-mapping/DefaultValues.php
Normal file
20
docs/en/reference/basic-mapping/DefaultValues.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
|
||||
#[Entity]
|
||||
class Message
|
||||
{
|
||||
#[Column(options: ['default' => 'Hello World!'])]
|
||||
private string $text;
|
||||
|
||||
#[Column(options: ['default' => new CurrentTimestamp()], insertable: false, updatable: false)]
|
||||
private DateTime $createdAt;
|
||||
}
|
||||
16
docs/en/reference/basic-mapping/default-values.xml
Normal file
16
docs/en/reference/basic-mapping/default-values.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<doctrine-mapping>
|
||||
<entity name="Message">
|
||||
<field name="text">
|
||||
<options>
|
||||
<option name="default">Hello World!</option>
|
||||
</options>
|
||||
</field>
|
||||
<field name="createdAt" insertable="false" updatable="false">
|
||||
<options>
|
||||
<option name="default">
|
||||
<object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp"/>
|
||||
</option>
|
||||
</options>
|
||||
</field>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
@@ -56,7 +56,8 @@ access point to ORM functionality provided by Doctrine.
|
||||
'dbname' => 'foo',
|
||||
];
|
||||
|
||||
$config = ORMSetup::createAttributeMetadataConfiguration($paths, $isDevMode);
|
||||
$config = ORMSetup::createAttributeMetadataConfig($paths, $isDevMode);
|
||||
// on PHP < 8.4, use ORMSetup::createAttributeMetadataConfiguration() instead
|
||||
$connection = DriverManager::getConnection($dbParams, $config);
|
||||
$entityManager = new EntityManager($connection, $config);
|
||||
|
||||
@@ -66,7 +67,8 @@ Or if you prefer XML:
|
||||
|
||||
<?php
|
||||
$paths = ['/path/to/xml-mappings'];
|
||||
$config = ORMSetup::createXMLMetadataConfiguration($paths, $isDevMode);
|
||||
$config = ORMSetup::createXMLMetadataConfig($paths, $isDevMode);
|
||||
// on PHP < 8.4, use ORMSetup::createXMLMetadataConfiguration() instead
|
||||
$connection = DriverManager::getConnection($dbParams, $config);
|
||||
$entityManager = new EntityManager($connection, $config);
|
||||
|
||||
|
||||
@@ -490,7 +490,7 @@ where you can generate an arbitrary join with the following syntax:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM User u JOIN Banlist b WITH u.email = b.email');
|
||||
$query = $em->createQuery('SELECT u FROM User u JOIN Banlist b ON u.email = b.email');
|
||||
|
||||
With an arbitrary join the result differs from the joins using a mapped property.
|
||||
The result of an arbitrary join is an one dimensional array with a mix of the entity from the ``SELECT``
|
||||
@@ -513,13 +513,15 @@ it loads all the related ``Banlist`` objects corresponding to this ``User``. Thi
|
||||
when the DQL is switched to an arbitrary join.
|
||||
|
||||
.. note::
|
||||
The differences between WHERE, WITH and HAVING clauses may be
|
||||
The differences between WHERE, WITH, ON and HAVING clauses may be
|
||||
confusing.
|
||||
|
||||
- WHERE is applied to the results of an entire query
|
||||
- WITH is applied to a join as an additional condition. For
|
||||
arbitrary joins (SELECT f, b FROM Foo f, Bar b WITH f.id = b.id)
|
||||
the WITH is required, even if it is 1 = 1
|
||||
- ON is applied to arbitrary joins as the join condition. For
|
||||
arbitrary joins (SELECT f, b FROM Foo f, Bar b ON f.id = b.id)
|
||||
the ON is required, even if it is 1 = 1. WITH is also
|
||||
supported as alternative keyword for that case for BC reasons.
|
||||
- WITH is applied to an association join as an additional condition.
|
||||
- HAVING is applied to the results of a query after
|
||||
aggregation (GROUP BY)
|
||||
|
||||
@@ -1409,8 +1411,7 @@ Result Cache API:
|
||||
|
||||
$query->setResultCacheDriver(new ApcCache());
|
||||
|
||||
$query->useResultCache(true)
|
||||
->setResultCacheLifeTime(3600);
|
||||
$query->enableResultCache(3600);
|
||||
|
||||
$result = $query->getResult(); // cache miss
|
||||
|
||||
@@ -1420,8 +1421,8 @@ Result Cache API:
|
||||
$query->setResultCacheId('my_query_result');
|
||||
$result = $query->getResult(); // saved in given result cache id.
|
||||
|
||||
// or call useResultCache() with all parameters:
|
||||
$query->useResultCache(true, 3600, 'my_query_result');
|
||||
// or call enableResultCache() with all parameters:
|
||||
$query->enableResultCache(3600, 'my_query_result');
|
||||
$result = $query->getResult(); // cache hit!
|
||||
|
||||
// Introspection
|
||||
@@ -1699,9 +1700,14 @@ From, Join and Index by
|
||||
SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration
|
||||
RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
|
||||
JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy]
|
||||
Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" (JoinAssociationDeclaration | RangeVariableDeclaration) ["WITH" ConditionalExpression]
|
||||
Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" (JoinAssociationDeclaration ["WITH" ConditionalExpression] | RangeVariableDeclaration [("ON" | "WITH") ConditionalExpression])
|
||||
IndexBy ::= "INDEX" "BY" SingleValuedPathExpression
|
||||
|
||||
.. note::
|
||||
Using the ``WITH`` keyword for the ``ConditionalExpression`` of a
|
||||
``RangeVariableDeclaration`` is deprecated and will be removed in
|
||||
ORM 4.0. Use the ``ON`` keyword instead.
|
||||
|
||||
Select Expressions
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -18,30 +18,6 @@ In your mapping configuration, the column definition (for example, the
|
||||
the ``charset`` and ``collation``. The default values are ``utf8`` and
|
||||
``utf8_unicode_ci``, respectively.
|
||||
|
||||
Entity Classes
|
||||
--------------
|
||||
|
||||
How can I add default values to a column?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Doctrine does not support to set the default values in columns through the "DEFAULT" keyword in SQL.
|
||||
This is not necessary however, you can just use your class properties as default values. These are then used
|
||||
upon insert:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
class User
|
||||
{
|
||||
private const STATUS_DISABLED = 0;
|
||||
private const STATUS_ENABLED = 1;
|
||||
|
||||
private string $algorithm = "sha1";
|
||||
/** @var self::STATUS_* */
|
||||
private int $status = self::STATUS_DISABLED;
|
||||
}
|
||||
|
||||
.
|
||||
|
||||
Mapping
|
||||
-------
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ table alias of the SQL table of the entity.
|
||||
|
||||
For the filter to correctly function, the following rules must be followed. Failure to do so will lead to unexpected results from the query cache.
|
||||
1. Parameters for the query should be set on the filter object by ``SQLFilter#setParameter()`` before the filter is used by the ORM ( i.e. do not set parameters inside ``SQLFilter#addFilterConstraint()`` function ).
|
||||
2. The filter must be deterministic. Don't change the values base on external inputs.
|
||||
2. The filter must be deterministic. Don't change the values based on external inputs.
|
||||
|
||||
The ``SQLFilter#getParameter()`` function takes care of the proper quoting of parameters.
|
||||
|
||||
|
||||
@@ -208,6 +208,22 @@ Example:
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
<entity name="MyProject\Model\Person" inheritance-type="SINGLE_TABLE">
|
||||
<discriminator-column name="discr" type="string" />
|
||||
<discriminator-map>
|
||||
<discriminator-mapping value="person" class="MyProject\Model\Person"/>
|
||||
<discriminator-mapping value="employee" class="MyProject\Model\Employee"/>
|
||||
</discriminator-map>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
<doctrine-mapping>
|
||||
<entity name="MyProject\Model\Employee">
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
In this example, the ``#[DiscriminatorMap]`` specifies that in the
|
||||
discriminator column, a value of "person" identifies a row as being of type
|
||||
|
||||
@@ -178,6 +178,14 @@ internally by the ORM currently refers to fields by their name only, without tak
|
||||
class containing the field into consideration. This makes it impossible to keep separate
|
||||
mapping configuration for both fields.
|
||||
|
||||
Apart from that, in the case of having multiple ``private`` fields of the same name within
|
||||
the class hierarchy an entity or mapped superclass, the Collection filtering API cannot determine
|
||||
the right field to look at. Even if only one of these fields is actually mapped, the ``ArrayCollection``
|
||||
will not be able to tell, since it does not have access to any metadata.
|
||||
|
||||
Thus, to avoid problems in this regard, it is best to avoid having multiple ``private`` fields of the
|
||||
same name in class hierarchies containing entity and mapped superclasses.
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
|
||||
@@ -209,6 +209,7 @@ Field & Association Getters
|
||||
|
||||
- ``isUniqueField($fieldName)``
|
||||
- ``isNullable($fieldName)``
|
||||
- ``isIndexed($fieldName)``
|
||||
- ``getColumnName($fieldName)``
|
||||
- ``getFieldMapping($fieldName)``
|
||||
- ``getAssociationMapping($fieldName)``
|
||||
|
||||
@@ -344,10 +344,10 @@ the Query object which can be retrieved from ``EntityManager#createQuery()``.
|
||||
Executing a Query
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
The QueryBuilder is a builder object only - it has no means of actually
|
||||
executing the Query. Additionally a set of parameters such as query hints
|
||||
cannot be set on the QueryBuilder itself. This is why you always have to convert
|
||||
a querybuilder instance into a Query object:
|
||||
The QueryBuilder is only a builder object - it has no means of actually
|
||||
executing the Query. Additional functionality, such as enabling the result cache,
|
||||
cannot be set on the QueryBuilder itself. This is why you must always convert
|
||||
a QueryBuilder instance into a Query object:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -355,9 +355,8 @@ a querybuilder instance into a Query object:
|
||||
// $qb instanceof QueryBuilder
|
||||
$query = $qb->getQuery();
|
||||
|
||||
// Set additional Query options
|
||||
$query->setQueryHint('foo', 'bar');
|
||||
$query->useResultCache('my_cache_id');
|
||||
// Enable the result cache
|
||||
$query->enableResultCache(3600, 'my_custom_id');
|
||||
|
||||
// Execute Query
|
||||
$result = $query->getResult();
|
||||
@@ -555,6 +554,24 @@ using ``addCriteria``:
|
||||
$qb->addCriteria($criteria);
|
||||
// then execute your query like normal
|
||||
|
||||
Adding hints to a Query
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can also set query hints to a QueryBuilder by using ``setHint``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// ...
|
||||
|
||||
// $qb instanceof QueryBuilder
|
||||
$qb->setHint('hintName', 'hintValue');
|
||||
// then execute your query like normal
|
||||
|
||||
The query hint can hold anything the usual query hints can hold
|
||||
except null. Those hints will be applied to the query when the
|
||||
query is created.
|
||||
|
||||
Low Level API
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ Something like below for an entity region:
|
||||
|
||||
|
||||
If the entity holds a collection that also needs to be cached.
|
||||
An collection region could look something like:
|
||||
A collection region could look something like:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -133,7 +133,7 @@ Caching mode
|
||||
* Read Write cache employs locks before update/delete.
|
||||
* Use if data needs to be updated.
|
||||
* Slowest strategy.
|
||||
* To use it a the cache region implementation must support locking.
|
||||
* To use it the cache region implementation must support locking.
|
||||
|
||||
|
||||
Built-in cached persisters
|
||||
@@ -518,7 +518,7 @@ DELETE / UPDATE queries
|
||||
DQL UPDATE / DELETE statements are ported directly into a database and bypass
|
||||
the second-level cache.
|
||||
Entities that are already cached will NOT be invalidated.
|
||||
However the cached data could be evicted using the cache API or an special query hint.
|
||||
However the cached data could be evicted using the cache API or a special query hint.
|
||||
|
||||
|
||||
Execute the ``UPDATE`` and invalidate ``all cache entries`` using ``Query::HINT_CACHE_EVICT``
|
||||
|
||||
@@ -118,7 +118,7 @@ entity might look like this:
|
||||
}
|
||||
}
|
||||
|
||||
Now the possiblity of mass-assignment exists on this entity and can
|
||||
Now the possibility of mass-assignment exists on this entity and can
|
||||
be exploited by attackers to set the "isAdmin" flag to true on any
|
||||
object when you pass the whole request data to this method like:
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ have to register them yourself.
|
||||
All the commands of the Doctrine Console require access to the
|
||||
``EntityManager``. You have to inject it into the console application.
|
||||
|
||||
Here is an example of a the project-specific ``bin/doctrine`` binary.
|
||||
Here is an example of a project-specific ``bin/doctrine`` binary.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -83,8 +83,6 @@ The following Commands are currently available:
|
||||
cache drivers.
|
||||
- ``orm:clear-cache:result`` Clear result cache of the various
|
||||
cache drivers.
|
||||
- ``orm:generate-proxies`` Generates proxy classes for entity
|
||||
classes.
|
||||
- ``orm:run-dql`` Executes arbitrary DQL directly from the command
|
||||
line.
|
||||
- ``orm:schema-tool:create`` Processes the schema and either
|
||||
@@ -96,6 +94,10 @@ The following Commands are currently available:
|
||||
- ``orm:schema-tool:update`` Processes the schema and either
|
||||
update the database schema of EntityManager Storage Connection or
|
||||
generate the SQL output.
|
||||
- ``orm:debug:event-manager`` Lists event listeners for an entity
|
||||
manager, optionally filtered by event name.
|
||||
- ``orm:debug:entity-listeners`` Lists entity listeners for a given
|
||||
entity, optionally filtered by event name.
|
||||
|
||||
The following alias is defined:
|
||||
|
||||
|
||||
@@ -112,7 +112,6 @@ of several common elements:
|
||||
|
||||
<indexes>
|
||||
<index name="name_idx" columns="name"/>
|
||||
<index columns="user_email"/>
|
||||
</indexes>
|
||||
|
||||
<unique-constraints>
|
||||
@@ -131,7 +130,7 @@ of several common elements:
|
||||
</id>
|
||||
|
||||
<field name="name" column="name" type="string" length="50" nullable="true" unique="true" />
|
||||
<field name="email" column="user_email" type="string" column-definition="CHAR(32) NOT NULL" />
|
||||
<field name="email" column="user_email" type="string" index="true" column-definition="CHAR(32) NOT NULL" />
|
||||
|
||||
<one-to-one field="address" target-entity="Address" inversed-by="user">
|
||||
<cascade><cascade-remove /></cascade>
|
||||
@@ -255,6 +254,8 @@ Optional attributes:
|
||||
only.
|
||||
- unique - Should this field contain a unique value across the
|
||||
table? Defaults to false.
|
||||
- index - Should an index be created for this column? Defaults to
|
||||
false.
|
||||
- nullable - Should this field allow NULL as a value? Defaults to
|
||||
false.
|
||||
- insertable - Should this field be inserted? Defaults to true.
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
: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
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
Getting Started: Database First
|
||||
===============================
|
||||
|
||||
.. note:: *Development Workflows*
|
||||
|
||||
When you :doc:`Code First <getting-started>`, you
|
||||
start with developing Objects and then map them onto your database. When
|
||||
you :doc:`Model First <getting-started-models>`, you are modelling your application using tools (for
|
||||
example UML) and generate database schema and PHP code from this model.
|
||||
When you have a Database First, you already have a database schema
|
||||
and generate the corresponding PHP code from it.
|
||||
|
||||
.. note::
|
||||
|
||||
This getting started guide is in development.
|
||||
|
||||
Development of new applications often starts with an existing database schema.
|
||||
When the database schema is the starting point for your application, then
|
||||
development is said to use the *Database First* approach to Doctrine.
|
||||
|
||||
In this workflow you would modify the database schema first and then
|
||||
regenerate the PHP code to use with this schema. You need a flexible
|
||||
code-generator for this task.
|
||||
|
||||
We spun off a subproject, Doctrine CodeGenerator, that will fill this gap and
|
||||
allow you to do *Database First* development.
|
||||
@@ -1,24 +0,0 @@
|
||||
Getting Started: Model First
|
||||
============================
|
||||
|
||||
.. note:: *Development Workflows*
|
||||
|
||||
When you :doc:`Code First <getting-started>`, you
|
||||
start with developing Objects and then map them onto your database. When
|
||||
you Model First, you are modelling your application using tools (for
|
||||
example UML) and generate database schema and PHP code from this model.
|
||||
When you have a :doc:`Database First <getting-started-database>`, then you already have a database schema
|
||||
and generate the corresponding PHP code from it.
|
||||
|
||||
.. note::
|
||||
|
||||
This getting started guide is in development.
|
||||
|
||||
There are applications when you start with a high-level description of the
|
||||
model using modelling tools such as UML. Modelling tools could also be Excel,
|
||||
XML or CSV files that describe the model in some structured way. If your
|
||||
application is using a modelling tool, then the development workflow is said to
|
||||
be a *Model First* approach to Doctrine2.
|
||||
|
||||
In this workflow you always change the model description and then regenerate
|
||||
both PHP code and database schema from this model.
|
||||
@@ -49,8 +49,7 @@ An entity contains persistable properties. A persistable property
|
||||
is an instance variable of the entity that is saved into and retrieved from the database
|
||||
by Doctrine's data mapping capabilities.
|
||||
|
||||
An entity class must not be final nor read-only, although
|
||||
it can contain final methods or read-only properties.
|
||||
An entity class can be final or read-only. It may contain final methods or read-only properties too.
|
||||
|
||||
An Example Model: Bug Tracker
|
||||
-----------------------------
|
||||
@@ -138,12 +137,12 @@ step:
|
||||
require_once "vendor/autoload.php";
|
||||
|
||||
// Create a simple "default" Doctrine ORM configuration for Attributes
|
||||
$config = ORMSetup::createAttributeMetadataConfiguration(
|
||||
$config = ORMSetup::createAttributeMetadataConfig( // on PHP < 8.4, use ORMSetup::createAttributeMetadataConfiguration()
|
||||
paths: [__DIR__ . '/src'],
|
||||
isDevMode: true,
|
||||
);
|
||||
// or if you prefer XML
|
||||
// $config = ORMSetup::createXMLMetadataConfiguration(
|
||||
// $config = ORMSetup::createXMLMetadataConfig( // on PHP < 8.4, use ORMSetup::createXMLMetadataConfiguration()
|
||||
// paths: [__DIR__ . '/config/xml'],
|
||||
// isDevMode: true,
|
||||
//);
|
||||
@@ -534,7 +533,7 @@ the ``id`` tag. It has a ``generator`` tag nested inside, which
|
||||
specifies that the primary key generation mechanism should automatically
|
||||
use the database platform's native id generation strategy (for
|
||||
example, AUTO INCREMENT in the case of MySql, or Sequences in the
|
||||
case of PostgreSql and Oracle).
|
||||
case of PostgreSQL and Oracle).
|
||||
|
||||
Now that we have defined our first entity and its metadata,
|
||||
let's update the database schema:
|
||||
@@ -1287,7 +1286,7 @@ The console output of this script is then:
|
||||
result set to retrieve entities from the database. DQL boils down to a
|
||||
Native SQL statement and a ``ResultSetMapping`` instance itself. Using
|
||||
Native SQL you could even use stored procedures for data retrieval, or
|
||||
make use of advanced non-portable database queries like PostgreSql's
|
||||
make use of advanced non-portable database queries like PostgreSQL's
|
||||
recursive queries.
|
||||
|
||||
|
||||
|
||||
@@ -155,10 +155,20 @@
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="object">
|
||||
<xs:attribute name="class" type="xs:string" use="required"/>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="option" mixed="true">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="option" type="orm:option"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
<xs:choice minOccurs="0" maxOccurs="1">
|
||||
<xs:element name="object" type="orm:object"/>
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="option" type="orm:option"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required"/>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
@@ -243,6 +253,7 @@
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="unique" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="nullable" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="index" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="insertable" type="xs:boolean" default="true" />
|
||||
<xs:attribute name="updatable" type="xs:boolean" default="true" />
|
||||
<xs:attribute name="generated" type="orm:generated-type" default="NEVER" />
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<!-- Ignore warnings, show progress of the run and show sniff names -->
|
||||
<arg value="nps"/>
|
||||
|
||||
<config name="php_version" value="80100"/>
|
||||
<config name="php_version" value="80400"/>
|
||||
|
||||
<file>src</file>
|
||||
<file>tests</file>
|
||||
@@ -50,8 +50,6 @@
|
||||
</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>
|
||||
|
||||
@@ -210,12 +208,6 @@
|
||||
<exclude-pattern>tests/Tests/Models/DDC1590/DDC1590User.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
|
||||
<rule ref="Squiz.Classes.ValidClassName.NotCamelCaps">
|
||||
<!-- we need to test what happens with an stdClass proxy -->
|
||||
<exclude-pattern>tests/Tests/Proxy/DefaultProxyClassNameResolverTest.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.Commenting.FunctionComment.WrongStyle">
|
||||
<!-- https://github.com/squizlabs/PHP_CodeSniffer/issues/1961 -->
|
||||
<exclude-pattern>tests/Tests/Mocks/DatabasePlatformMock.php</exclude-pattern>
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: '#^Expression "\$setCacheEntry\(\$data\)" on a separate line does not do anything\.$#'
|
||||
identifier: expr.resultUnused
|
||||
count: 1
|
||||
path: src/AbstractQuery.php
|
||||
|
||||
-
|
||||
message: '#^Expression "\$setCacheEntry\(\$stmt\)" on a separate line does not do anything\.$#'
|
||||
identifier: expr.resultUnused
|
||||
count: 1
|
||||
path: src/AbstractQuery.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\AbstractQuery\:\:getParameter\(\) should return Doctrine\\ORM\\Query\\Parameter\|null but returns Doctrine\\ORM\\Query\\Parameter\|false\|null\.$#'
|
||||
identifier: return.type
|
||||
@@ -234,12 +222,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Cache/DefaultQueryCache.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$result of class Doctrine\\ORM\\Cache\\QueryCacheEntry constructor expects array\<string, mixed\>, array\<int\|string, array\<string, array\<mixed\>\>\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Cache/DefaultQueryCache.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$key of method Doctrine\\ORM\\Cache\\Logging\\CacheLogger\:\:entityCacheHit\(\) expects Doctrine\\ORM\\Cache\\EntityCacheKey, Doctrine\\ORM\\Cache\\CacheKey given\.$#'
|
||||
identifier: argument.type
|
||||
@@ -516,6 +498,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Cache/TimestampQueryCacheValidator.php
|
||||
|
||||
-
|
||||
message: '#^Call to function is_a\(\) with arguments class\-string\<Doctrine\\ORM\\EntityRepository\>, ''Doctrine\\\\ORM\\\\EntityRepository'' and true will always evaluate to true\.$#'
|
||||
identifier: function.alreadyNarrowedType
|
||||
count: 1
|
||||
path: src/Configuration.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Configuration\:\:getDefaultRepositoryClassName\(\) return type with generic class Doctrine\\ORM\\EntityRepository does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -558,12 +546,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Decorator/EntityManagerDecorator.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method object\:\:setEntityManager\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: src/EntityManager.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\EntityManager\:\:checkLockRequirements\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -637,7 +619,7 @@ parameters:
|
||||
path: src/EntityRepository.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\EntityRepository\:\:matching\(\) should return Doctrine\\Common\\Collections\\AbstractLazyCollection\<int, T of object\>&Doctrine\\Common\\Collections\\Selectable\<int, T of object\> but returns Doctrine\\ORM\\LazyCriteriaCollection\<\(int\|string\), object\>\.$#'
|
||||
message: '#^Method Doctrine\\ORM\\EntityRepository\:\:matching\(\) should return Doctrine\\Common\\Collections\\AbstractLazyCollection\<int, T of object\> but returns Doctrine\\ORM\\LazyCriteriaCollection\<\(int\|string\), object\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/EntityRepository.php
|
||||
@@ -733,13 +715,13 @@ parameters:
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
|
||||
-
|
||||
message: '#^Parameter &\$id by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, string\>, array\<int\|string, string\> given\.$#'
|
||||
message: '#^Parameter &\$id by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, string\>, array\<string\> given\.$#'
|
||||
identifier: parameterByRef.type
|
||||
count: 1
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
|
||||
-
|
||||
message: '#^Parameter &\$nonemptyComponents by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, bool\>, array\<int\|string, bool\> given\.$#'
|
||||
message: '#^Parameter &\$nonemptyComponents by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, bool\>, array\<bool\> given\.$#'
|
||||
identifier: parameterByRef.type
|
||||
count: 1
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
@@ -834,6 +816,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Internal/HydrationCompleteHandler.php
|
||||
|
||||
-
|
||||
message: '#^Offset int\|null might not exist on array\<int, object\>\.$#'
|
||||
identifier: offsetAccess.notFound
|
||||
count: 1
|
||||
path: src/Internal/StronglyConnectedComponents.php
|
||||
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Internal\\StronglyConnectedComponents\:\:\$representingNodes \(array\<int, object\>\) does not accept array\<int\|string, object\>\.$#'
|
||||
identifier: assign.propertyType
|
||||
@@ -954,12 +942,6 @@ parameters:
|
||||
count: 4
|
||||
path: src/Mapping/ClassMetadata.php
|
||||
|
||||
-
|
||||
message: '#^If condition is always true\.$#'
|
||||
identifier: if.alwaysTrue
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadata.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\ClassMetadata\:\:inlineEmbeddable\(\) has parameter \$embeddable with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -1080,6 +1062,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadata.php
|
||||
|
||||
-
|
||||
message: '#^Template type T is declared as covariant, but occurs in invariant position in return type of method Doctrine\\ORM\\Mapping\\ClassMetadata\:\:getReflectionClass\(\)\.$#'
|
||||
identifier: generics.variance
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadata.php
|
||||
|
||||
-
|
||||
message: '#^Unable to resolve the template type C in call to method Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:fullyQualifiedClassName\(\)$#'
|
||||
identifier: argument.templateType
|
||||
@@ -1314,6 +1302,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Mapping/DefaultQuoteStrategy.php
|
||||
|
||||
-
|
||||
message: '#^Expression on left side of \?\? is not nullable\.$#'
|
||||
identifier: nullCoalesce.expr
|
||||
count: 1
|
||||
path: src/Mapping/Driver/AttributeDriver.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\AttributeDriver\:\:isRepeatedPropertyDeclaration\(\) has parameter \$metadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -1332,132 +1326,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Mapping/Driver/AttributeDriver.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencedColumnNames\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencedTableName\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencingColumnNames\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\Index\:\:getIndexedColumns\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\Table\:\:getPrimaryKeyConstraint\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Call to method getColumnName\(\) on an unknown class Doctrine\\DBAL\\Schema\\Index\\IndexedColumn\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Call to method getColumnNames\(\) on an unknown class Doctrine\\DBAL\\Schema\\PrimaryKeyConstraint\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Call to method toString\(\) on an unknown class Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName\.$#'
|
||||
identifier: class.notFound
|
||||
count: 5
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Cannot call method getName\(\) on Doctrine\\DBAL\\Schema\\Column\|false\.$#'
|
||||
identifier: method.nonObject
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Class Doctrine\\DBAL\\Schema\\Index\\IndexType not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Class Doctrine\\DBAL\\Schema\\PrimaryKeyConstraint not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Instanceof between Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\> and Doctrine\\ORM\\Mapping\\ClassMetadata will always evaluate to true\.$#'
|
||||
identifier: instanceof.alwaysTrue
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:__construct\(\) has parameter \$sm with generic class Doctrine\\DBAL\\Schema\\AbstractSchemaManager but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:buildFieldMappings\(\) has parameter \$metadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:buildIndexes\(\) has parameter \$metadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:buildToOneAssociationMappings\(\) has parameter \$metadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:getClassNameForTable\(\) should return class\-string but returns string\.$#'
|
||||
identifier: return.type
|
||||
count: 2
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$array of function sort contains unresolvable type\.$#'
|
||||
identifier: argument.unresolvableType
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$columnName of method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:getFieldNameForColumn\(\) expects string, string\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 4
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \$indexedColumn of anonymous function has invalid type Doctrine\\DBAL\\Schema\\Index\\IndexedColumn\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \$name of anonymous function has invalid type Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName\.$#'
|
||||
identifier: class.notFound
|
||||
count: 5
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\SimplifiedXmlDriver\:\:__construct\(\) has parameter \$fileExtension with no type specified\.$#'
|
||||
identifier: missingType.parameter
|
||||
@@ -1483,7 +1351,7 @@ parameters:
|
||||
path: src/Mapping/Driver/XmlDriver.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$columnDef of method Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:setDiscriminatorColumn\(\) expects array\{name\: string\|null, fieldName\?\: string\|null, type\?\: string\|null, length\?\: int\|null, columnDefinition\?\: string\|null, enumType\?\: class\-string\<BackedEnum\>\|null, options\?\: array\<string, mixed\>\|null\}\|Doctrine\\ORM\\Mapping\\DiscriminatorColumnMapping\|null, array\{name\: string\|null, type\: string, length\: int, columnDefinition\: string\|null, enumType\: string\|null, options\?\: array\<int\|string, array\<int\|string, mixed\>\|bool\|string\>\} given\.$#'
|
||||
message: '#^Parameter \#1 \$columnDef of method Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:setDiscriminatorColumn\(\) expects array\{name\: string\|null, fieldName\?\: string\|null, type\?\: string\|null, length\?\: int\|null, columnDefinition\?\: string\|null, enumType\?\: class\-string\<BackedEnum\>\|null, options\?\: array\<string, mixed\>\|null\}\|Doctrine\\ORM\\Mapping\\DiscriminatorColumnMapping\|null, array\{name\: string\|null, type\: string, length\: int, columnDefinition\: string\|null, enumType\: string\|null, options\?\: array\<int\|string, array\<int\|string, mixed\>\|bool\|object\|string\>\} given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Mapping/Driver/XmlDriver.php
|
||||
@@ -1513,7 +1381,7 @@ parameters:
|
||||
path: src/Mapping/Driver/XmlDriver.php
|
||||
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:\$table \(array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\?\: array\<string, mixed\>, quoted\?\: bool\}\) does not accept array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\: array\<int\|string, array\<int\|string, mixed\>\|bool\|string\>, quoted\?\: bool\}\.$#'
|
||||
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:\$table \(array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\?\: array\<string, mixed\>, quoted\?\: bool\}\) does not accept array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\: array\<int\|string, array\<int\|string, mixed\>\|bool\|object\|string\>, quoted\?\: bool\}\.$#'
|
||||
identifier: assign.propertyType
|
||||
count: 1
|
||||
path: src/Mapping/Driver/XmlDriver.php
|
||||
@@ -1561,16 +1429,10 @@ parameters:
|
||||
path: src/Mapping/JoinTableMapping.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\LegacyReflectionFields\:\:__construct\(\) has parameter \$classMetadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
message: '#^Strict comparison using \!\=\= between array\<string, string\> and null will always evaluate to true\.$#'
|
||||
identifier: notIdentical.alwaysTrue
|
||||
count: 1
|
||||
path: src/Mapping/LegacyReflectionFields.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$class of method Doctrine\\Persistence\\Mapping\\ReflectionService\:\:getAccessibleProperty\(\) expects class\-string, string given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Mapping/LegacyReflectionFields.php
|
||||
path: src/Mapping/ManyToManyOwningSideMapping.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\MappedSuperclass\:\:__construct\(\) has parameter \$repositoryClass with generic class Doctrine\\ORM\\EntityRepository but does not specify its types\: T$#'
|
||||
@@ -1638,12 +1500,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Mapping/QuoteStrategy.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\ReflectionEnumProperty\:\:getValue\(\) return type has no value type specified in iterable type array\.$#'
|
||||
identifier: missingType.iterableValue
|
||||
count: 1
|
||||
path: src/Mapping/ReflectionEnumProperty.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Mapping\\ToOneOwningSideMapping\:\:fromMappingArray\(\) should return static\(Doctrine\\ORM\\Mapping\\ToOneOwningSideMapping\) but returns Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\.$#'
|
||||
identifier: return.type
|
||||
@@ -1717,7 +1573,7 @@ parameters:
|
||||
path: src/PersistentCollection.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\PersistentCollection\:\:matching\(\) should return Doctrine\\Common\\Collections\\Collection\<TKey of \(int\|string\), T\> but returns Doctrine\\Common\\Collections\\ReadableCollection\<TKey of \(int\|string\), T\>&Doctrine\\Common\\Collections\\Selectable\<TKey of \(int\|string\), T\>\.$#'
|
||||
message: '#^Method Doctrine\\ORM\\PersistentCollection\:\:matching\(\) should return Doctrine\\Common\\Collections\\Collection\<TKey of \(int\|string\), T\> but returns Doctrine\\Common\\Collections\\ReadableCollection\<TKey of \(int\|string\), T\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/PersistentCollection.php
|
||||
@@ -1729,7 +1585,7 @@ parameters:
|
||||
path: src/PersistentCollection.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$callback of function array_walk expects callable\(object, int\)\: mixed, array\{Doctrine\\Common\\Collections\\Collection\<TKey of \(int\|string\), T\>&Doctrine\\Common\\Collections\\Selectable\<TKey of \(int\|string\), T\>, ''add''\} given\.$#'
|
||||
message: '#^Parameter \#2 \$callback of function array_walk expects callable\(object, int\)\: mixed, array\{Doctrine\\Common\\Collections\\Collection\<TKey of \(int\|string\), T\>, ''add''\} given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/PersistentCollection.php
|
||||
@@ -1854,6 +1710,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Collection/ManyToManyPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Collection\\ManyToManyPersister\:\:count\(\) should return int\<0, max\> but returns int\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Persisters/Collection/ManyToManyPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Collection\\ManyToManyPersister\:\:delete\(\) has parameter \$collection with generic class Doctrine\\ORM\\PersistentCollection but does not specify its types\: TKey, T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -2022,6 +1884,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Collection/OneToManyPersister.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$columns of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getColumnDeclarationListSQL\(\) expects list\<array\{name\: string, type\: Doctrine\\DBAL\\Types\\Type, default\: mixed, notnull\?\: bool, autoincrement\: bool, columnDefinition\: non\-empty\-string\|null, comment\: string, charset\?\: non\-empty\-string\|null, \.\.\.\}\>, array\<string, array\{name\: string, notnull\: true, type\: Doctrine\\DBAL\\Types\\Type\}\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Persisters/Collection/OneToManyPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\AbstractEntityInheritancePersister\:\:getSelectColumnSQL\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -2052,18 +1920,6 @@ parameters:
|
||||
count: 4
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$relationToTargetKeyColumns\.$#'
|
||||
identifier: property.notFound
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$sourceToTargetKeyColumns\.$#'
|
||||
identifier: property.notFound
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:indexBy\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
@@ -2076,18 +1932,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:expandCriteriaParameters\(\) should return array\{list\<mixed\>, list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|Doctrine\\DBAL\\ParameterType\:\:ASCII\|Doctrine\\DBAL\\ParameterType\:\:BINARY\|Doctrine\\DBAL\\ParameterType\:\:BOOLEAN\|Doctrine\\DBAL\\ParameterType\:\:INTEGER\|Doctrine\\DBAL\\ParameterType\:\:LARGE_OBJECT\|Doctrine\\DBAL\\ParameterType\:\:NULL\|Doctrine\\DBAL\\ParameterType\:\:STRING\|string\>\} but returns array\{array\<mixed\>, list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|Doctrine\\DBAL\\ParameterType\:\:ASCII\|Doctrine\\DBAL\\ParameterType\:\:BINARY\|Doctrine\\DBAL\\ParameterType\:\:BOOLEAN\|Doctrine\\DBAL\\ParameterType\:\:INTEGER\|Doctrine\\DBAL\\ParameterType\:\:LARGE_OBJECT\|Doctrine\\DBAL\\ParameterType\:\:NULL\|Doctrine\\DBAL\\ParameterType\:\:STRING\|string\>\}\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:expandParameters\(\) should return array\{list\<mixed\>, list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|Doctrine\\DBAL\\ParameterType\:\:ASCII\|Doctrine\\DBAL\\ParameterType\:\:BINARY\|Doctrine\\DBAL\\ParameterType\:\:BOOLEAN\|Doctrine\\DBAL\\ParameterType\:\:INTEGER\|Doctrine\\DBAL\\ParameterType\:\:LARGE_OBJECT\|Doctrine\\DBAL\\ParameterType\:\:NULL\|Doctrine\\DBAL\\ParameterType\:\:STRING\|string\>\} but returns array\{array\<mixed\>, list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|Doctrine\\DBAL\\ParameterType\:\:ASCII\|Doctrine\\DBAL\\ParameterType\:\:BINARY\|Doctrine\\DBAL\\ParameterType\:\:BOOLEAN\|Doctrine\\DBAL\\ParameterType\:\:INTEGER\|Doctrine\\DBAL\\ParameterType\:\:LARGE_OBJECT\|Doctrine\\DBAL\\ParameterType\:\:NULL\|Doctrine\\DBAL\\ParameterType\:\:STRING\|string\>\}\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:expandToManyParameters\(\) return type has no value type specified in iterable type array\.$#'
|
||||
identifier: missingType.iterableValue
|
||||
@@ -2124,12 +1968,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getIndividualValue\(\) should return list\<mixed\> but returns array\<mixed\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getSelectColumnAssociationSQL\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -2142,18 +1980,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getTypes\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getTypes\(\) should return list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|Doctrine\\DBAL\\ParameterType\:\:ASCII\|Doctrine\\DBAL\\ParameterType\:\:BINARY\|Doctrine\\DBAL\\ParameterType\:\:BOOLEAN\|Doctrine\\DBAL\\ParameterType\:\:INTEGER\|Doctrine\\DBAL\\ParameterType\:\:LARGE_OBJECT\|Doctrine\\DBAL\\ParameterType\:\:NULL\|Doctrine\\DBAL\\ParameterType\:\:STRING\|string\> but returns list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|int\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:loadCollectionFromStatement\(\) has parameter \$coll with generic class Doctrine\\ORM\\PersistentCollection but does not specify its types\: TKey, T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -2178,12 +2004,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$lockMode of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:appendLockHint\(\) expects Doctrine\\DBAL\\LockMode, Doctrine\\DBAL\\LockMode\:\:NONE\|Doctrine\\DBAL\\LockMode\:\:OPTIMISTIC\|Doctrine\\DBAL\\LockMode\:\:PESSIMISTIC_READ\|Doctrine\\DBAL\\LockMode\:\:PESSIMISTIC_WRITE\|int given\.$#'
|
||||
identifier: argument.type
|
||||
count: 2
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#3 \$hints of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:hydrateAll\(\) expects array\<string, string\>, array\<string, Doctrine\\ORM\\PersistentCollection\|true\> given\.$#'
|
||||
identifier: argument.type
|
||||
@@ -2208,12 +2028,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Strict comparison using \=\=\= between string and null will always evaluate to false\.$#'
|
||||
identifier: identical.alwaysFalse
|
||||
count: 1
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\CachedPersisterContext\:\:__construct\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -2262,12 +2076,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/Entity/JoinedSubclassPersister.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$lockMode of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:appendLockHint\(\) expects Doctrine\\DBAL\\LockMode, Doctrine\\DBAL\\LockMode\:\:NONE\|Doctrine\\DBAL\\LockMode\:\:OPTIMISTIC\|Doctrine\\DBAL\\LockMode\:\:PESSIMISTIC_READ\|Doctrine\\DBAL\\LockMode\:\:PESSIMISTIC_WRITE\|int given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Persisters/Entity/JoinedSubclassPersister.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$joinColumns\.$#'
|
||||
identifier: property.notFound
|
||||
@@ -2292,156 +2100,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Persisters/SqlValueVisitor.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#3 \$className of static method Doctrine\\ORM\\Proxy\\Autoloader\:\:resolveFile\(\) expects class\-string, string given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Proxy/Autoloader.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#3 of closure expects class\-string, string given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Proxy/Autoloader.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\DefaultProxyClassNameResolver\:\:resolveClassName\(\) should return class\-string\<T of object\> but returns class\-string\<Doctrine\\Persistence\\Proxy\<T of object\>\>\|class\-string\<T of object\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Proxy/DefaultProxyClassNameResolver.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\DefaultProxyClassNameResolver\:\:resolveClassName\(\) should return class\-string\<T of object\> but returns string\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Proxy/DefaultProxyClassNameResolver.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\Persistence\\Mapping\\ClassMetadata\:\:\$isEmbeddedClass\.$#'
|
||||
identifier: property.notFound
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\Persistence\\Mapping\\ClassMetadata\:\:\$isMappedSuperclass\.$#'
|
||||
identifier: property.notFound
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined static method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createLazyGhost\(\)\.$#'
|
||||
identifier: staticMethod.notFound
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Call to function is_bool\(\) with bool will always evaluate to true\.$#'
|
||||
identifier: function.alreadyNarrowedType
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Comparison operation "\<" between 0\|1\|2\|3\|4 and 0 is always false\.$#'
|
||||
identifier: smaller.alwaysFalse
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Comparison operation "\>" between 0\|1\|2\|3\|4 and 4 is always false\.$#'
|
||||
identifier: greater.alwaysFalse
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createLazyInitializer\(\) has Doctrine\\ORM\\EntityNotFoundException in PHPDoc @throws tag but it''s not thrown\.$#'
|
||||
identifier: throws.unusedType
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createLazyInitializer\(\) has parameter \$classMetadata with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createLazyInitializer\(\) return type has no value type specified in iterable type array\.$#'
|
||||
identifier: missingType.iterableValue
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createLazyInitializer\(\) return type with generic interface Doctrine\\ORM\\Proxy\\InternalProxy does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateProxyClass\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateProxyClasses\(\) has parameter \$classes with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateSerializeImpl\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateUseLazyGhostTrait\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:loadProxyClass\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:skipClass\(\) has parameter \$metadata with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$class of method Doctrine\\ORM\\Utility\\IdentifierFlattener\:\:flattenIdentifier\(\) expects Doctrine\\ORM\\Mapping\\ClassMetadata, Doctrine\\Persistence\\Mapping\\ClassMetadata given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$filename of function filemtime expects string, string\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#3 \$length of function substr expects int\|null, int\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#3 \$newScope of static method Closure\:\:bind\(\) expects ''static''\|class\-string\|object\|null, string given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Result of \|\| is always false\.$#'
|
||||
identifier: booleanOr.alwaysFalse
|
||||
count: 1
|
||||
path: src/Proxy/ProxyFactory.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Query\:\:processParameterMappings\(\) return type has no value type specified in iterable type array\.$#'
|
||||
identifier: missingType.iterableValue
|
||||
@@ -2562,12 +2220,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Query/AST/Functions/SizeFunction.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$mode of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getTrimExpression\(\) expects Doctrine\\DBAL\\Platforms\\TrimMode, Doctrine\\DBAL\\Platforms\\TrimMode\:\:BOTH\|Doctrine\\DBAL\\Platforms\\TrimMode\:\:LEADING\|Doctrine\\DBAL\\Platforms\\TrimMode\:\:TRAILING\|Doctrine\\DBAL\\Platforms\\TrimMode\:\:UNSPECIFIED\|int given\.$#'
|
||||
identifier: argument.type
|
||||
count: 2
|
||||
path: src/Query/AST/Functions/TrimFunction.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\ORM\\Query\\SqlWalker\:\:walkJoinPathExpression\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
@@ -2610,6 +2262,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Query/Exec/MultiTableDeleteExecutor.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$columns of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getColumnDeclarationListSQL\(\) expects list\<array\{name\: string, type\: Doctrine\\DBAL\\Types\\Type, default\: mixed, notnull\?\: bool, autoincrement\: bool, columnDefinition\: non\-empty\-string\|null, comment\: string, charset\?\: non\-empty\-string\|null, \.\.\.\}\>, array\<string, array\{name\: string, notnull\: true, type\: Doctrine\\DBAL\\Types\\Type\}\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Query/Exec/MultiTableDeleteExecutor.php
|
||||
|
||||
-
|
||||
message: '#^Argument of an invalid type list\<string\>\|string supplied for foreach, only iterables are supported\.$#'
|
||||
identifier: foreach.nonIterable
|
||||
@@ -2623,7 +2281,7 @@ parameters:
|
||||
path: src/Query/Exec/MultiTableUpdateExecutor.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#3 \$types of method Doctrine\\DBAL\\Connection\:\:executeStatement\(\) expects array\<int\<0, max\>\|string, Doctrine\\DBAL\\ArrayParameterType\|Doctrine\\DBAL\\ParameterType\|Doctrine\\DBAL\\Types\\Type\|string\>, list\<Doctrine\\DBAL\\ArrayParameterType\|Doctrine\\DBAL\\ParameterType\|Doctrine\\DBAL\\Types\\Type\|int\|string\> given\.$#'
|
||||
message: '#^Parameter \#1 \$columns of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getColumnDeclarationListSQL\(\) expects list\<array\{name\: string, type\: Doctrine\\DBAL\\Types\\Type, default\: mixed, notnull\?\: bool, autoincrement\: bool, columnDefinition\: non\-empty\-string\|null, comment\: string, charset\?\: non\-empty\-string\|null, \.\.\.\}\>, array\<string, array\{name\: string, notnull\: true, type\: Doctrine\\DBAL\\Types\\Type\}\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Query/Exec/MultiTableUpdateExecutor.php
|
||||
@@ -2646,42 +2304,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Query/Exec/SingleTableDeleteUpdateExecutor.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc type array\<string\> of property Doctrine\\ORM\\Query\\Expr\\Andx\:\:\$allowedClasses is not covariant with PHPDoc type list\<class\-string\> of overridden property Doctrine\\ORM\\Query\\Expr\\Base\:\:\$allowedClasses\.$#'
|
||||
identifier: property.phpDocType
|
||||
count: 1
|
||||
path: src/Query/Expr/Andx.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Query\\Expr\\Func\:\:getArguments\(\) should return list\<mixed\> but returns array\<mixed\>\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Query/Expr/Func.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc type array\<string\> of property Doctrine\\ORM\\Query\\Expr\\Orx\:\:\$allowedClasses is not covariant with PHPDoc type list\<class\-string\> of overridden property Doctrine\\ORM\\Query\\Expr\\Base\:\:\$allowedClasses\.$#'
|
||||
identifier: property.phpDocType
|
||||
count: 1
|
||||
path: src/Query/Expr/Orx.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc type array\<string\> of property Doctrine\\ORM\\Query\\Expr\\Select\:\:\$allowedClasses is not covariant with PHPDoc type list\<class\-string\> of overridden property Doctrine\\ORM\\Query\\Expr\\Base\:\:\$allowedClasses\.$#'
|
||||
identifier: property.phpDocType
|
||||
count: 1
|
||||
path: src/Query/Expr/Select.php
|
||||
|
||||
-
|
||||
message: '#^Property Doctrine\\ORM\\Query\\Filter\\SQLFilter\:\:\$parameters \(array\<string, array\{type\: string, value\: mixed, is_list\: bool\}\>\) does not accept non\-empty\-array\<string, array\{value\: mixed, type\: Doctrine\\DBAL\\ArrayParameterType\|Doctrine\\DBAL\\ParameterType\|int\|string, is_list\: bool\}\>\.$#'
|
||||
identifier: assign.propertyType
|
||||
count: 1
|
||||
path: src/Query/Filter/SQLFilter.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Query\\ParameterTypeInferer\:\:inferType\(\) never returns int so it can be removed from the return type\.$#'
|
||||
identifier: return.unusedType
|
||||
count: 1
|
||||
path: src/Query/ParameterTypeInferer.php
|
||||
|
||||
-
|
||||
message: '#^@readonly property cannot have a default value\.$#'
|
||||
identifier: property.readOnlyByPhpDocDefaultValue
|
||||
@@ -2916,6 +2544,12 @@ parameters:
|
||||
count: 2
|
||||
path: src/QueryBuilder.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#3 \$type of method Doctrine\\ORM\\QueryBuilder\:\:setParameter\(\) expects Doctrine\\DBAL\\ArrayParameterType\|Doctrine\\DBAL\\ParameterType\|string\|null, Doctrine\\DBAL\\ArrayParameterType\|Doctrine\\DBAL\\ParameterType\|int\|string\|null given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/QueryBuilder.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Repository\\DefaultRepositoryFactory\:\:createRepository\(\) return type with generic class Doctrine\\ORM\\EntityRepository does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -2928,30 +2562,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Repository/DefaultRepositoryFactory.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\Persistence\\Mapping\\ClassMetadata\:\:\$name\.$#'
|
||||
identifier: property.notFound
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/GenerateProxiesCommand.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$filename of function file_exists expects string, string\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/GenerateProxiesCommand.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$filename of function is_writable expects string, string\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/GenerateProxiesCommand.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$proxyDir of method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateProxyClasses\(\) expects string\|null, string\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/GenerateProxiesCommand.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Tools\\Console\\Command\\MappingDescribeCommand\:\:getClassMetadata\(\) return type with generic class Doctrine\\ORM\\Mapping\\ClassMetadata does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -3108,12 +2718,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Tools/ResolveTargetEntityListener.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$className of method Doctrine\\Persistence\\Mapping\\AbstractClassMetadataFactory\<Doctrine\\ORM\\Mapping\\ClassMetadata\>\:\:setMetadataFor\(\) expects class\-string, \(int\|string\) given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/ResolveTargetEntityListener.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$joinColumns\.$#'
|
||||
identifier: property.notFound
|
||||
@@ -3121,32 +2725,71 @@ parameters:
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencedColumnNames\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
message: '''
|
||||
#^Call to deprecated method getColumns\(\) of class Doctrine\\DBAL\\Schema\\Index\:
|
||||
Use \{@see getIndexedColumns\(\)\} instead\.$#
|
||||
'''
|
||||
identifier: method.deprecated
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencedTableName\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
message: '''
|
||||
#^Call to deprecated method getForeignColumns\(\) of class Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:
|
||||
Use \{@see getReferencedColumnNames\(\)\} instead\.
|
||||
|
||||
Returns the names of the referenced table columns
|
||||
the foreign key constraint is associated with\.$#
|
||||
'''
|
||||
identifier: method.deprecated
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencingColumnNames\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
message: '''
|
||||
#^Call to deprecated method getForeignTableName\(\) of class Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:
|
||||
Use \{@see getReferencedTableName\(\)\} instead\.
|
||||
|
||||
Returns the name of the referenced table
|
||||
the foreign key constraint is associated with\.$#
|
||||
'''
|
||||
identifier: method.deprecated
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\Index\:\:getIndexedColumns\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
message: '''
|
||||
#^Call to deprecated method getLocalColumns\(\) of class Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:
|
||||
Use \{@see getReferencingColumnNames\(\)\} instead\.$#
|
||||
'''
|
||||
identifier: method.deprecated
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\Table\:\:dropForeignKey\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
message: '''
|
||||
#^Call to deprecated method getPrimaryKey\(\) of class Doctrine\\DBAL\\Schema\\Table\:
|
||||
Use \{@see getPrimaryKeyConstraint\(\)\} instead\.$#
|
||||
'''
|
||||
identifier: method.deprecated
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '''
|
||||
#^Call to deprecated method removeForeignKey\(\) of class Doctrine\\DBAL\\Schema\\Table\:
|
||||
Use \{@link dropForeignKey\(\)\} instead\.$#
|
||||
'''
|
||||
identifier: method.deprecated
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '''
|
||||
#^Call to deprecated method setPrimaryKey\(\) of class Doctrine\\DBAL\\Schema\\Table\:
|
||||
Use \{@see addPrimaryKeyConstraint\(\)\} instead\.$#
|
||||
'''
|
||||
identifier: method.deprecated
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
@@ -3157,32 +2800,14 @@ parameters:
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Call to method getColumnName\(\) on an unknown class Doctrine\\DBAL\\Schema\\Index\\IndexedColumn\.$#'
|
||||
identifier: class.notFound
|
||||
message: '#^Call to function method_exists\(\) with ''Doctrine\\\\DBAL\\\\Schema\\\\Index'' and ''getIndexedColumns'' will always evaluate to true\.$#'
|
||||
identifier: function.alreadyNarrowedType
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Call to method getColumnNames\(\) on an unknown class Doctrine\\DBAL\\Schema\\PrimaryKeyConstraint\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Call to method toString\(\) on an unknown class Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName\.$#'
|
||||
identifier: class.notFound
|
||||
count: 3
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Class Doctrine\\DBAL\\Schema\\PrimaryKeyConstraint not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\DBAL\\Schema\\AbstractSchemaManager\<Doctrine\\DBAL\\Platforms\\AbstractPlatform\>\:\:createComparator\(\) invoked with 1 parameter, 0 required\.$#'
|
||||
identifier: arguments.count
|
||||
message: '#^Call to function method_exists\(\) with Doctrine\\DBAL\\Schema\\Table and ''getPrimaryKeyConstr…'' will always evaluate to true\.$#'
|
||||
identifier: function.alreadyNarrowedType
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
@@ -3228,6 +2853,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Tools\\SchemaTool\:\:getAssetName\(\) has parameter \$asset with generic class Doctrine\\DBAL\\Schema\\AbstractAsset but does not specify its types\: N$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Tools\\SchemaTool\:\:getCreateSchemaSql\(\) has parameter \$classes with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -3289,15 +2920,45 @@ parameters:
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \$indexedColumn of anonymous function has invalid type Doctrine\\DBAL\\Schema\\Index\\IndexedColumn\.$#'
|
||||
identifier: class.notFound
|
||||
message: '#^Parameter \#1 \$columnNames of method Doctrine\\DBAL\\Schema\\Table\:\:addIndex\(\) expects non\-empty\-list\<string\>, list\<string\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \$name of anonymous function has invalid type Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName\.$#'
|
||||
identifier: class.notFound
|
||||
count: 3
|
||||
message: '#^Parameter \#1 \$columnNames of method Doctrine\\DBAL\\Schema\\Table\:\:addUniqueIndex\(\) expects non\-empty\-list\<string\>, array\<string\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$columns of class Doctrine\\DBAL\\Schema\\Index constructor expects non\-empty\-list\<string\>, list\<string\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$localColumnNames of method Doctrine\\DBAL\\Schema\\Table\:\:addForeignKeyConstraint\(\) expects non\-empty\-list\<string\>, list\<string\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$primaryKeyColumns of method Doctrine\\ORM\\Tools\\SchemaTool\:\:addPrimaryKeyConstraint\(\) expects non\-empty\-array\<non\-empty\-string\>, list\<string\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 2
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$primaryKeyColumns of method Doctrine\\ORM\\Tools\\SchemaTool\:\:addPrimaryKeyConstraint\(\) expects non\-empty\-array\<non\-empty\-string\>, non\-empty\-list\<string\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#3 \$foreignColumnNames of method Doctrine\\DBAL\\Schema\\Table\:\:addForeignKeyConstraint\(\) expects non\-empty\-list\<string\>, list\<string\> given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
@@ -3366,6 +3027,12 @@ parameters:
|
||||
count: 1
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\AssociationMapping\:\:\$joinColumns\.$#'
|
||||
identifier: property.notFound
|
||||
count: 1
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$inversedBy\.$#'
|
||||
identifier: property.notFound
|
||||
@@ -3381,7 +3048,7 @@ parameters:
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$mappedBy\.$#'
|
||||
identifier: property.notFound
|
||||
count: 1
|
||||
count: 3
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
@@ -3450,12 +3117,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc tag @phpstan\-assert\-if\-true for \$obj contains generic interface Doctrine\\ORM\\Proxy\\InternalProxy but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#2 \$assoc of method Doctrine\\ORM\\PersistentCollection\<\(int\|string\),mixed\>\:\:setOwner\(\) expects Doctrine\\ORM\\Mapping\\AssociationMapping&Doctrine\\ORM\\Mapping\\ToManyAssociationMapping, Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping given\.$#'
|
||||
identifier: argument.type
|
||||
@@ -3474,12 +3135,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#3 \$collection of class Doctrine\\ORM\\PersistentCollection constructor expects Doctrine\\Common\\Collections\\Collection\<\(int\|string\), mixed\>&Doctrine\\Common\\Collections\\Selectable\<\(int\|string\), mixed\>, Doctrine\\Common\\Collections\\Collection given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#5 \$invoke of method Doctrine\\ORM\\Event\\ListenersInvoker\:\:invoke\(\) expects int\<0, 7\>, int\<min, \-1\>\|int\<1, max\> given\.$#'
|
||||
identifier: argument.type
|
||||
@@ -3558,6 +3213,18 @@ parameters:
|
||||
count: 1
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$relationToTargetKeyColumns\.$#'
|
||||
identifier: property.notFound
|
||||
count: 1
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
-
|
||||
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$sourceToTargetKeyColumns\.$#'
|
||||
identifier: property.notFound
|
||||
count: 1
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Utility\\PersisterHelper\:\:getTypeOfColumn\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
@@ -3569,3 +3236,9 @@ parameters:
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Utility\\PersisterHelper\:\:inferParameterTypes\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
|
||||
identifier: missingType.generics
|
||||
count: 1
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
includes:
|
||||
- phpstan-baseline.neon
|
||||
- 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\.$/'
|
||||
|
||||
# We can be certain that those values are not matched.
|
||||
-
|
||||
message: '~^Match expression does not handle remaining values:~'
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
# DBAL 4 compatibility
|
||||
-
|
||||
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: '~.*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\.$~'
|
||||
|
||||
# To be removed in 4.0
|
||||
-
|
||||
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
|
||||
55
phpstan.neon
55
phpstan.neon
@@ -3,6 +3,8 @@ includes:
|
||||
- phpstan-params.neon
|
||||
|
||||
parameters:
|
||||
checkMissingOverrideMethodAttribute: true
|
||||
|
||||
ignoreErrors:
|
||||
# Symfony cache supports passing a key prefix to the clear method.
|
||||
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
|
||||
@@ -10,55 +12,4 @@ parameters:
|
||||
# We can be certain that those values are not matched.
|
||||
-
|
||||
message: '~^Match expression does not handle remaining values:~'
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
# DBAL 4 compatibility
|
||||
-
|
||||
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: '~^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
|
||||
-
|
||||
message: '~^Result of method Doctrine\\DBAL\\Connection::commit\(\) \(void\) is used\.$~'
|
||||
path: src/UnitOfWork.php
|
||||
-
|
||||
message: '~^Strict comparison using === between null and false will always evaluate to false\.$~'
|
||||
path: src/UnitOfWork.php
|
||||
-
|
||||
message: '~^Variable \$e on left side of \?\? always exists and is not nullable\.$~'
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '~^Parameter #2 \$command of static method Doctrine\\ORM\\Tools\\Console\\ConsoleRunner::addCommandToApplication\(\) expects Symfony\\Component\\Console\\Command\\Command, Doctrine\\DBAL\\Tools\\Console\\Command\\ReservedWordsCommand given\.$~'
|
||||
path: src/Tools/Console/ConsoleRunner.php
|
||||
|
||||
-
|
||||
message: '~Strict comparison using \=\=\= between callable\(\)\: mixed and null will always evaluate to false\.~'
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
# To be removed in 4.0
|
||||
-
|
||||
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
|
||||
path: src/Utility/PersisterHelper.php
|
||||
|
||||
21
run-all.sh
21
run-all.sh
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script is a small convenience wrapper for running the doctrine testsuite against a large bunch of databases.
|
||||
# Just create the phpunit.xmls as described in the array below and configure the specific files <php /> section
|
||||
# to connect to that database. Just omit a file if you don't have that database and the tests will be skipped.
|
||||
|
||||
configs[1]="mysql.phpunit.xml"
|
||||
configs[2]='postgres.phpunit.xml'
|
||||
configs[3]='sqlite.phpunit.xml'
|
||||
configs[4]='oracle.phpunit.xml'
|
||||
configs[5]='db2.phpunit.xml'
|
||||
configs[6]='pdo-ibm.phpunit.xml'
|
||||
configs[7]='sqlsrv.phpunit.xml'
|
||||
|
||||
for i in "${configs[@]}"; do
|
||||
if [ -f "$i" ];
|
||||
then
|
||||
echo "RUNNING TESTS WITH CONFIG $i"
|
||||
phpunit -c "$i" "$@"
|
||||
fi;
|
||||
done
|
||||
@@ -16,9 +16,7 @@ use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
use Doctrine\ORM\Cache\TimestampCacheKey;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Doctrine\ORM\Query\Parameter;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\Persistence\Mapping\MappingException;
|
||||
use LogicException;
|
||||
@@ -52,32 +50,32 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Hydrates an object graph. This is the default behavior.
|
||||
*/
|
||||
public const HYDRATE_OBJECT = 1;
|
||||
final public const int HYDRATE_OBJECT = 1;
|
||||
|
||||
/**
|
||||
* Hydrates an array graph.
|
||||
*/
|
||||
public const HYDRATE_ARRAY = 2;
|
||||
final public const int HYDRATE_ARRAY = 2;
|
||||
|
||||
/**
|
||||
* Hydrates a flat, rectangular result set with scalar values.
|
||||
*/
|
||||
public const HYDRATE_SCALAR = 3;
|
||||
final public const int HYDRATE_SCALAR = 3;
|
||||
|
||||
/**
|
||||
* Hydrates a single scalar value.
|
||||
*/
|
||||
public const HYDRATE_SINGLE_SCALAR = 4;
|
||||
final public const int HYDRATE_SINGLE_SCALAR = 4;
|
||||
|
||||
/**
|
||||
* Very simple object hydrator (optimized for performance).
|
||||
*/
|
||||
public const HYDRATE_SIMPLEOBJECT = 5;
|
||||
final public const int HYDRATE_SIMPLEOBJECT = 5;
|
||||
|
||||
/**
|
||||
* Hydrates scalar column value.
|
||||
*/
|
||||
public const HYDRATE_SCALAR_COLUMN = 6;
|
||||
final public const int HYDRATE_SCALAR_COLUMN = 6;
|
||||
|
||||
/**
|
||||
* The parameter map of this query.
|
||||
@@ -321,16 +319,16 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Sets a query parameter.
|
||||
*
|
||||
* @param string|int $key The parameter position or name.
|
||||
* @param mixed $value The parameter value.
|
||||
* @param ParameterType|ArrayParameterType|string|int|null $type The parameter type. If specified, the given value
|
||||
* will be run through the type conversion of this
|
||||
* type. This is usually not needed for strings and
|
||||
* numeric types.
|
||||
* @param string|int $key The parameter position or name.
|
||||
* @param mixed $value The parameter value.
|
||||
* @param ParameterType|ArrayParameterType|string|null $type The parameter type. If specified, the given value
|
||||
* will be run through the type conversion of this
|
||||
* type. This is usually not needed for strings and
|
||||
* numeric types.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setParameter(string|int $key, mixed $value, ParameterType|ArrayParameterType|string|int|null $type = null): static
|
||||
public function setParameter(string|int $key, mixed $value, ParameterType|ArrayParameterType|string|null $type = null): static
|
||||
{
|
||||
$existingParameter = $this->getParameter($key);
|
||||
|
||||
@@ -379,7 +377,7 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
try {
|
||||
$class = DefaultProxyClassNameResolver::getClass($value);
|
||||
$class = $value::class;
|
||||
$value = $this->em->getUnitOfWork()->getSingleIdentifierValue($value);
|
||||
|
||||
if ($value === null) {
|
||||
@@ -865,10 +863,6 @@ abstract class AbstractQuery
|
||||
throw new LogicException('Uninitialized result set mapping.');
|
||||
}
|
||||
|
||||
if ($rsm->isMixed && count($rsm->scalarMappings) > 0) {
|
||||
throw QueryException::iterateWithMixedResultNotAllowed();
|
||||
}
|
||||
|
||||
$stmt = $this->_doExecute();
|
||||
|
||||
return $this->em->newHydrator($this->hydrationMode)->toIterable($stmt, $rsm, $this->hints);
|
||||
@@ -1070,7 +1064,7 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query and returns a the resulting Statement object.
|
||||
* Executes the query and returns the resulting Statement object.
|
||||
*
|
||||
* @return Result|int The executed database statement that holds
|
||||
* the results, or an integer indicating how
|
||||
|
||||
@@ -12,31 +12,31 @@ use Doctrine\ORM\Cache\Region;
|
||||
*/
|
||||
interface Cache
|
||||
{
|
||||
public const DEFAULT_QUERY_REGION_NAME = 'query_cache_region';
|
||||
final public const string DEFAULT_QUERY_REGION_NAME = 'query_cache_region';
|
||||
|
||||
public const DEFAULT_TIMESTAMP_REGION_NAME = 'timestamp_cache_region';
|
||||
final public const string DEFAULT_TIMESTAMP_REGION_NAME = 'timestamp_cache_region';
|
||||
|
||||
/**
|
||||
* May read items from the cache, but will not add items.
|
||||
*/
|
||||
public const MODE_GET = 1;
|
||||
final public const int MODE_GET = 1;
|
||||
|
||||
/**
|
||||
* Will never read items from the cache,
|
||||
* but will add items to the cache as it reads them from the database.
|
||||
*/
|
||||
public const MODE_PUT = 2;
|
||||
final public const int MODE_PUT = 2;
|
||||
|
||||
/**
|
||||
* May read items from the cache, and add items to the cache.
|
||||
*/
|
||||
public const MODE_NORMAL = 3;
|
||||
final public const int MODE_NORMAL = 3;
|
||||
|
||||
/**
|
||||
* The query will never read items from the cache,
|
||||
* but will refresh items to the cache as it reads them from the database.
|
||||
*/
|
||||
public const MODE_REFRESH = 4;
|
||||
final public const int MODE_REFRESH = 4;
|
||||
|
||||
public function getEntityCacheRegion(string $className): Region|null;
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ use Doctrine\ORM\Cache\Persister\CachedPersister;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\ORMInvalidArgumentException;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Override;
|
||||
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
@@ -40,6 +40,7 @@ class DefaultCache implements Cache
|
||||
->getCacheFactory();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getEntityCacheRegion(string $className): Region|null
|
||||
{
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
@@ -52,6 +53,7 @@ class DefaultCache implements Cache
|
||||
return $persister->getCacheRegion();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getCollectionCacheRegion(string $className, string $association): Region|null
|
||||
{
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
@@ -64,6 +66,7 @@ class DefaultCache implements Cache
|
||||
return $persister->getCacheRegion();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function containsEntity(string $className, mixed $identifier): bool
|
||||
{
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
@@ -76,6 +79,7 @@ class DefaultCache implements Cache
|
||||
return $persister->getCacheRegion()->contains($this->buildEntityCacheKey($metadata, $identifier));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evictEntity(string $className, mixed $identifier): void
|
||||
{
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
@@ -88,6 +92,7 @@ class DefaultCache implements Cache
|
||||
$persister->getCacheRegion()->evict($this->buildEntityCacheKey($metadata, $identifier));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evictEntityRegion(string $className): void
|
||||
{
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
@@ -100,6 +105,7 @@ class DefaultCache implements Cache
|
||||
$persister->getCacheRegion()->evictAll();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evictEntityRegions(): void
|
||||
{
|
||||
$metadatas = $this->em->getMetadataFactory()->getAllMetadata();
|
||||
@@ -115,6 +121,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function containsCollection(string $className, string $association, mixed $ownerIdentifier): bool
|
||||
{
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
@@ -127,6 +134,7 @@ class DefaultCache implements Cache
|
||||
return $persister->getCacheRegion()->contains($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evictCollection(string $className, string $association, mixed $ownerIdentifier): void
|
||||
{
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
@@ -139,6 +147,7 @@ class DefaultCache implements Cache
|
||||
$persister->getCacheRegion()->evict($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evictCollectionRegion(string $className, string $association): void
|
||||
{
|
||||
$metadata = $this->em->getClassMetadata($className);
|
||||
@@ -151,6 +160,7 @@ class DefaultCache implements Cache
|
||||
$persister->getCacheRegion()->evictAll();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evictCollectionRegions(): void
|
||||
{
|
||||
$metadatas = $this->em->getMetadataFactory()->getAllMetadata();
|
||||
@@ -172,11 +182,13 @@ class DefaultCache implements Cache
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function containsQuery(string $regionName): bool
|
||||
{
|
||||
return isset($this->queryCaches[$regionName]);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evictQueryRegion(string|null $regionName = null): void
|
||||
{
|
||||
if ($regionName === null && $this->defaultQueryCache !== null) {
|
||||
@@ -190,6 +202,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evictQueryRegions(): void
|
||||
{
|
||||
$this->getQueryCache()->clear();
|
||||
@@ -199,6 +212,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getQueryCache(string|null $regionName = null): QueryCache
|
||||
{
|
||||
if ($regionName === null) {
|
||||
@@ -233,7 +247,7 @@ class DefaultCache implements Cache
|
||||
private function toIdentifierArray(ClassMetadata $metadata, mixed $identifier): array
|
||||
{
|
||||
if (is_object($identifier)) {
|
||||
$class = DefaultProxyClassNameResolver::getClass($identifier);
|
||||
$class = $identifier::class;
|
||||
if ($this->em->getMetadataFactory()->hasMetadataFor($class)) {
|
||||
$identifier = $this->uow->getSingleIdentifierValue($identifier)
|
||||
?? throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($class);
|
||||
|
||||
@@ -23,6 +23,7 @@ use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use Override;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
use function assert;
|
||||
@@ -63,6 +64,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
$this->timestampRegion = $region;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata): CachedEntityPersister
|
||||
{
|
||||
assert($metadata->cache !== null);
|
||||
@@ -88,6 +90,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function buildCachedCollectionPersister(
|
||||
EntityManagerInterface $em,
|
||||
CollectionPersister $persister,
|
||||
@@ -116,6 +119,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function buildQueryCache(EntityManagerInterface $em, string|null $regionName = null): QueryCache
|
||||
{
|
||||
return new DefaultQueryCache(
|
||||
@@ -129,11 +133,13 @@ class DefaultCacheFactory implements CacheFactory
|
||||
);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function buildCollectionHydrator(EntityManagerInterface $em, AssociationMapping $mapping): CollectionHydrator
|
||||
{
|
||||
return new DefaultCollectionHydrator($em);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata): EntityHydrator
|
||||
{
|
||||
return new DefaultEntityHydrator($em);
|
||||
@@ -142,6 +148,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function getRegion(array $cache): Region
|
||||
{
|
||||
if (isset($this->regions[$cache['region']])) {
|
||||
@@ -170,6 +177,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
return $this->regions[$cache['region']] = $region;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getTimestampRegion(): TimestampRegion
|
||||
{
|
||||
if ($this->timestampRegion === null) {
|
||||
@@ -182,6 +190,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
return $this->timestampRegion;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function createCache(EntityManagerInterface $entityManager): Cache
|
||||
{
|
||||
return new DefaultCache($entityManager);
|
||||
|
||||
@@ -11,6 +11,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Override;
|
||||
|
||||
use function assert;
|
||||
|
||||
@@ -30,6 +31,7 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, array|Collection $collection): CollectionCacheEntry
|
||||
{
|
||||
$data = [];
|
||||
@@ -41,6 +43,7 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
return new CollectionCacheEntry($data);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection): array|null
|
||||
{
|
||||
$assoc = $metadata->associationMappings[$key->association];
|
||||
|
||||
@@ -6,10 +6,10 @@ namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\ORM\Utility\IdentifierFlattener;
|
||||
use Override;
|
||||
|
||||
use function assert;
|
||||
use function is_array;
|
||||
@@ -34,6 +34,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
$this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory());
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function buildCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, object $entity): EntityCacheEntry
|
||||
{
|
||||
$data = $this->uow->getOriginalEntityData($entity);
|
||||
@@ -97,7 +98,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
}
|
||||
|
||||
if (! isset($assoc->id)) {
|
||||
$targetClass = DefaultProxyClassNameResolver::getClass($data[$name]);
|
||||
$targetClass = $data[$name]::class;
|
||||
$targetId = $this->uow->getEntityIdentifier($data[$name]);
|
||||
$data[$name] = new AssociationCacheEntry($targetClass, $targetId);
|
||||
|
||||
@@ -125,6 +126,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
return new EntityCacheEntry($metadata->name, $data);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function loadCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, EntityCacheEntry $entry, object|null $entity = null): object|null
|
||||
{
|
||||
$data = $entry->data;
|
||||
|
||||
@@ -18,6 +18,7 @@ use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Override;
|
||||
|
||||
use function array_map;
|
||||
use function array_shift;
|
||||
@@ -54,6 +55,7 @@ class DefaultQueryCache implements QueryCache
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = []): array|null
|
||||
{
|
||||
if (! ($key->cacheMode & Cache::MODE_GET)) {
|
||||
@@ -197,6 +199,7 @@ class DefaultQueryCache implements QueryCache
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function put(QueryCacheKey $key, ResultSetMapping $rsm, mixed $result, array $hints = []): bool
|
||||
{
|
||||
if ($rsm->scalarMappings) {
|
||||
@@ -406,11 +409,13 @@ class DefaultQueryCache implements QueryCache
|
||||
return $values;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function clear(): bool
|
||||
{
|
||||
return $this->region->evictAll();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getRegion(): Region
|
||||
{
|
||||
return $this->region;
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Doctrine\ORM\Cache\Logging;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
use Override;
|
||||
|
||||
class CacheLoggerChain implements CacheLogger
|
||||
{
|
||||
@@ -29,6 +30,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
return $this->loggers;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function collectionCacheHit(string $regionName, CollectionCacheKey $key): void
|
||||
{
|
||||
foreach ($this->loggers as $logger) {
|
||||
@@ -36,6 +38,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function collectionCacheMiss(string $regionName, CollectionCacheKey $key): void
|
||||
{
|
||||
foreach ($this->loggers as $logger) {
|
||||
@@ -43,6 +46,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function collectionCachePut(string $regionName, CollectionCacheKey $key): void
|
||||
{
|
||||
foreach ($this->loggers as $logger) {
|
||||
@@ -50,6 +54,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function entityCacheHit(string $regionName, EntityCacheKey $key): void
|
||||
{
|
||||
foreach ($this->loggers as $logger) {
|
||||
@@ -57,6 +62,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function entityCacheMiss(string $regionName, EntityCacheKey $key): void
|
||||
{
|
||||
foreach ($this->loggers as $logger) {
|
||||
@@ -64,6 +70,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function entityCachePut(string $regionName, EntityCacheKey $key): void
|
||||
{
|
||||
foreach ($this->loggers as $logger) {
|
||||
@@ -71,6 +78,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function queryCacheHit(string $regionName, QueryCacheKey $key): void
|
||||
{
|
||||
foreach ($this->loggers as $logger) {
|
||||
@@ -78,6 +86,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function queryCacheMiss(string $regionName, QueryCacheKey $key): void
|
||||
{
|
||||
foreach ($this->loggers as $logger) {
|
||||
@@ -85,6 +94,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function queryCachePut(string $regionName, QueryCacheKey $key): void
|
||||
{
|
||||
foreach ($this->loggers as $logger) {
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Doctrine\ORM\Cache\Logging;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
use Override;
|
||||
|
||||
use function array_sum;
|
||||
|
||||
@@ -24,54 +25,63 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
/** @var array<string, int> */
|
||||
private array $cachePutCountMap = [];
|
||||
|
||||
#[Override]
|
||||
public function collectionCacheMiss(string $regionName, CollectionCacheKey $key): void
|
||||
{
|
||||
$this->cacheMissCountMap[$regionName]
|
||||
= ($this->cacheMissCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function collectionCacheHit(string $regionName, CollectionCacheKey $key): void
|
||||
{
|
||||
$this->cacheHitCountMap[$regionName]
|
||||
= ($this->cacheHitCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function collectionCachePut(string $regionName, CollectionCacheKey $key): void
|
||||
{
|
||||
$this->cachePutCountMap[$regionName]
|
||||
= ($this->cachePutCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function entityCacheMiss(string $regionName, EntityCacheKey $key): void
|
||||
{
|
||||
$this->cacheMissCountMap[$regionName]
|
||||
= ($this->cacheMissCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function entityCacheHit(string $regionName, EntityCacheKey $key): void
|
||||
{
|
||||
$this->cacheHitCountMap[$regionName]
|
||||
= ($this->cacheHitCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function entityCachePut(string $regionName, EntityCacheKey $key): void
|
||||
{
|
||||
$this->cachePutCountMap[$regionName]
|
||||
= ($this->cachePutCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function queryCacheHit(string $regionName, QueryCacheKey $key): void
|
||||
{
|
||||
$this->cacheHitCountMap[$regionName]
|
||||
= ($this->cacheHitCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function queryCacheMiss(string $regionName, QueryCacheKey $key): void
|
||||
{
|
||||
$this->cacheMissCountMap[$regionName]
|
||||
= ($this->cacheMissCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function queryCachePut(string $regionName, QueryCacheKey $key): void
|
||||
{
|
||||
$this->cachePutCountMap[$regionName]
|
||||
|
||||
@@ -17,9 +17,9 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
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 Override;
|
||||
|
||||
use function array_values;
|
||||
use function assert;
|
||||
@@ -63,21 +63,25 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
$this->targetEntity = $em->getClassMetadata($association->targetEntity);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getCacheRegion(): Region
|
||||
{
|
||||
return $this->region;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getSourceEntityMetadata(): ClassMetadata
|
||||
{
|
||||
return $this->sourceEntity;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getTargetEntityMetadata(): ClassMetadata
|
||||
{
|
||||
return $this->targetEntity;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key): array|null
|
||||
{
|
||||
$cache = $this->region->get($key);
|
||||
@@ -89,6 +93,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
return $this->hydrator->loadCacheEntry($this->sourceEntity, $key, $cache, $collection);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function storeCollectionCache(CollectionCacheKey $key, Collection|array $elements): void
|
||||
{
|
||||
$associationMapping = $this->sourceEntity->associationMappings[$key->association];
|
||||
@@ -111,7 +116,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
$class = $this->targetEntity;
|
||||
$className = DefaultProxyClassNameResolver::getClass($elements[$index]);
|
||||
$className = $elements[$index]::class;
|
||||
|
||||
if ($className !== $this->targetEntity->name) {
|
||||
$class = $this->metadataFactory->getMetadataFor($className);
|
||||
@@ -128,16 +133,19 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function contains(PersistentCollection $collection, object $element): bool
|
||||
{
|
||||
return $this->persister->contains($collection, $element);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function containsKey(PersistentCollection $collection, mixed $key): bool
|
||||
{
|
||||
return $this->persister->containsKey($collection, $key);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function count(PersistentCollection $collection): int
|
||||
{
|
||||
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
|
||||
@@ -151,6 +159,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
return $this->persister->count($collection);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function get(PersistentCollection $collection, mixed $index): mixed
|
||||
{
|
||||
return $this->persister->get($collection, $index);
|
||||
@@ -159,6 +168,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function slice(PersistentCollection $collection, int $offset, int|null $length = null): array
|
||||
{
|
||||
return $this->persister->slice($collection, $offset, $length);
|
||||
@@ -167,6 +177,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function loadCriteria(PersistentCollection $collection, Criteria $criteria): array
|
||||
{
|
||||
return $this->persister->loadCriteria($collection, $criteria);
|
||||
|
||||
@@ -6,11 +6,13 @@ namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Override;
|
||||
|
||||
use function spl_object_id;
|
||||
|
||||
class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
{
|
||||
#[Override]
|
||||
public function afterTransactionComplete(): void
|
||||
{
|
||||
if (isset($this->queuedCache['update'])) {
|
||||
@@ -28,11 +30,13 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
$this->queuedCache = [];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function afterTransactionRolledBack(): void
|
||||
{
|
||||
$this->queuedCache = [];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function delete(PersistentCollection $collection): void
|
||||
{
|
||||
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
|
||||
@@ -43,6 +47,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
$this->queuedCache['delete'][spl_object_id($collection)] = $key;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function update(PersistentCollection $collection): void
|
||||
{
|
||||
$isInitialized = $collection->isInitialized();
|
||||
|
||||
@@ -6,15 +6,16 @@ namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyCollection;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Override;
|
||||
|
||||
class ReadOnlyCachedCollectionPersister extends NonStrictReadWriteCachedCollectionPersister
|
||||
{
|
||||
#[Override]
|
||||
public function update(PersistentCollection $collection): void
|
||||
{
|
||||
if ($collection->isDirty() && $collection->getSnapshot()) {
|
||||
throw CannotUpdateReadOnlyCollection::fromEntityAndField(
|
||||
DefaultProxyClassNameResolver::getClass($collection->getOwner()),
|
||||
$collection->getOwner()::class,
|
||||
$this->association->fieldName,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\AssociationMapping;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Override;
|
||||
|
||||
use function spl_object_id;
|
||||
|
||||
@@ -24,6 +25,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
parent::__construct($persister, $region, $em, $association);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function afterTransactionComplete(): void
|
||||
{
|
||||
if (isset($this->queuedCache['update'])) {
|
||||
@@ -41,6 +43,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
$this->queuedCache = [];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function afterTransactionRolledBack(): void
|
||||
{
|
||||
if (isset($this->queuedCache['update'])) {
|
||||
@@ -58,6 +61,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
$this->queuedCache = [];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function delete(PersistentCollection $collection): void
|
||||
{
|
||||
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
|
||||
@@ -76,6 +80,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function update(PersistentCollection $collection): void
|
||||
{
|
||||
$isInitialized = $collection->isInitialized();
|
||||
|
||||
@@ -23,13 +23,12 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
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 Override;
|
||||
|
||||
use function array_merge;
|
||||
use function func_get_args;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
|
||||
@@ -77,6 +76,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
$this->timestampKey = new TimestampCacheKey($this->class->rootEntityName);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function addInsert(object $entity): void
|
||||
{
|
||||
$this->persister->addInsert($entity);
|
||||
@@ -85,15 +85,17 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function getInserts(): array
|
||||
{
|
||||
return $this->persister->getInserts();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getSelectSQL(
|
||||
array|Criteria $criteria,
|
||||
AssociationMapping|null $assoc = null,
|
||||
LockMode|int|null $lockMode = null,
|
||||
LockMode|null $lockMode = null,
|
||||
int|null $limit = null,
|
||||
int|null $offset = null,
|
||||
array|null $orderBy = null,
|
||||
@@ -101,21 +103,25 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
return $this->persister->getSelectSQL($criteria, $assoc, $lockMode, $limit, $offset, $orderBy);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getCountSQL(array|Criteria $criteria = []): string
|
||||
{
|
||||
return $this->persister->getCountSQL($criteria);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getInsertSQL(): string
|
||||
{
|
||||
return $this->persister->getInsertSQL();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getResultSetMapping(): ResultSetMapping
|
||||
{
|
||||
return $this->persister->getResultSetMapping();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getSelectConditionStatementSQL(
|
||||
string $field,
|
||||
mixed $value,
|
||||
@@ -125,6 +131,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
return $this->persister->getSelectConditionStatementSQL($field, $value, $assoc, $comparison);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function exists(object $entity, Criteria|null $extraConditions = null): bool
|
||||
{
|
||||
if ($extraConditions === null) {
|
||||
@@ -138,20 +145,23 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
return $this->persister->exists($entity, $extraConditions);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getCacheRegion(): Region
|
||||
{
|
||||
return $this->region;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getEntityHydrator(): EntityHydrator
|
||||
{
|
||||
return $this->hydrator;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function storeEntityCache(object $entity, EntityCacheKey $key): bool
|
||||
{
|
||||
$class = $this->class;
|
||||
$className = DefaultProxyClassNameResolver::getClass($entity);
|
||||
$className = $entity::class;
|
||||
|
||||
if ($className !== $this->class->name) {
|
||||
$class = $this->metadataFactory->getMetadataFor($className);
|
||||
@@ -225,6 +235,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function expandParameters(array $criteria): array
|
||||
{
|
||||
return $this->persister->expandParameters($criteria);
|
||||
@@ -233,11 +244,13 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function expandCriteriaParameters(Criteria $criteria): array
|
||||
{
|
||||
return $this->persister->expandCriteriaParameters($criteria);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getClassMetadata(): ClassMetadata
|
||||
{
|
||||
return $this->persister->getClassMetadata();
|
||||
@@ -246,6 +259,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function getManyToManyCollection(
|
||||
AssociationMapping $assoc,
|
||||
object $sourceEntity,
|
||||
@@ -258,6 +272,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function getOneToManyCollection(
|
||||
AssociationMapping $assoc,
|
||||
object $sourceEntity,
|
||||
@@ -267,11 +282,13 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
return $this->persister->getOneToManyCollection($assoc, $sourceEntity, $offset, $limit);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getOwningTable(string $fieldName): string
|
||||
{
|
||||
return $this->persister->getOwningTable($fieldName);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function executeInserts(): void
|
||||
{
|
||||
// The commit order/foreign key relationships may make it necessary that multiple calls to executeInsert()
|
||||
@@ -288,12 +305,13 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function load(
|
||||
array $criteria,
|
||||
object|null $entity = null,
|
||||
AssociationMapping|null $assoc = null,
|
||||
array $hints = [],
|
||||
LockMode|int|null $lockMode = null,
|
||||
LockMode|null $lockMode = null,
|
||||
int|null $limit = null,
|
||||
array|null $orderBy = null,
|
||||
): object|null {
|
||||
@@ -335,6 +353,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function loadAll(
|
||||
array $criteria = [],
|
||||
array|null $orderBy = null,
|
||||
@@ -371,6 +390,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function loadById(array $identifier, object|null $entity = null): object|null
|
||||
{
|
||||
$cacheKey = new EntityCacheKey($this->class->rootEntityName, $identifier);
|
||||
@@ -398,7 +418,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
$class = $this->class;
|
||||
$className = DefaultProxyClassNameResolver::getClass($entity);
|
||||
$className = $entity::class;
|
||||
|
||||
if ($className !== $this->class->name) {
|
||||
$class = $this->metadataFactory->getMetadataFor($className);
|
||||
@@ -420,6 +440,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
return $entity;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function count(array|Criteria $criteria = []): int
|
||||
{
|
||||
return $this->persister->count($criteria);
|
||||
@@ -428,6 +449,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function loadCriteria(Criteria $criteria): array
|
||||
{
|
||||
$orderBy = $criteria->orderings();
|
||||
@@ -463,6 +485,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function loadManyToManyCollection(
|
||||
AssociationMapping $assoc,
|
||||
object $sourceEntity,
|
||||
@@ -494,6 +517,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
return $list;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function loadOneToManyCollection(
|
||||
AssociationMapping $assoc,
|
||||
object $sourceEntity,
|
||||
@@ -528,6 +552,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function loadOneToOneEntity(AssociationMapping $assoc, object $sourceEntity, array $identifier = []): object|null
|
||||
{
|
||||
return $this->persister->loadOneToOneEntity($assoc, $sourceEntity, $identifier);
|
||||
@@ -536,7 +561,8 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function lock(array $criteria, LockMode|int $lockMode): void
|
||||
#[Override]
|
||||
public function lock(array $criteria, LockMode $lockMode): void
|
||||
{
|
||||
$this->persister->lock($criteria, $lockMode);
|
||||
}
|
||||
@@ -544,16 +570,15 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function refresh(array $id, object $entity, LockMode|int|null $lockMode = null): void
|
||||
#[Override]
|
||||
public function refresh(array $id, object $entity, LockMode|null $lockMode = null): void
|
||||
{
|
||||
$this->persister->refresh($id, $entity, $lockMode);
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $ownerId */
|
||||
protected function buildCollectionCacheKey(AssociationMapping $association, array $ownerId, /* string $filterHash */): CollectionCacheKey
|
||||
protected function buildCollectionCacheKey(AssociationMapping $association, array $ownerId, string $filterHash): CollectionCacheKey
|
||||
{
|
||||
$filterHash = (string) (func_get_args()[2] ?? ''); // todo: move to argument in next major release
|
||||
|
||||
return new CollectionCacheKey(
|
||||
$this->metadataFactory->getMetadataFor($association->sourceEntity)->rootEntityName,
|
||||
$association->fieldName,
|
||||
|
||||
@@ -5,12 +5,14 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Specific non-strict read/write cached entity persister
|
||||
*/
|
||||
class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
{
|
||||
#[Override]
|
||||
public function afterTransactionComplete(): void
|
||||
{
|
||||
$isChanged = false;
|
||||
@@ -42,11 +44,13 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
$this->queuedCache = [];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function afterTransactionRolledBack(): void
|
||||
{
|
||||
$this->queuedCache = [];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function delete(object $entity): bool
|
||||
{
|
||||
$key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity));
|
||||
@@ -61,6 +65,7 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function update(object $entity): void
|
||||
{
|
||||
$this->persister->update($entity);
|
||||
|
||||
@@ -5,15 +5,16 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyEntity;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Specific read-only region entity persister
|
||||
*/
|
||||
class ReadOnlyCachedEntityPersister extends NonStrictReadWriteCachedEntityPersister
|
||||
{
|
||||
#[Override]
|
||||
public function update(object $entity): void
|
||||
{
|
||||
throw CannotUpdateReadOnlyEntity::fromEntity(DefaultProxyClassNameResolver::getClass($entity));
|
||||
throw CannotUpdateReadOnlyEntity::fromEntity($entity::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Specific read-write entity persister
|
||||
@@ -20,6 +21,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
parent::__construct($persister, $region, $em, $class);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function afterTransactionComplete(): void
|
||||
{
|
||||
$isChanged = true;
|
||||
@@ -47,6 +49,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
$this->queuedCache = [];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function afterTransactionRolledBack(): void
|
||||
{
|
||||
if (isset($this->queuedCache['update'])) {
|
||||
@@ -64,6 +67,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
$this->queuedCache = [];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function delete(object $entity): bool
|
||||
{
|
||||
$key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity));
|
||||
@@ -86,6 +90,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function update(object $entity): void
|
||||
{
|
||||
$key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity));
|
||||
|
||||
@@ -9,6 +9,7 @@ use Doctrine\ORM\Cache\CacheKey;
|
||||
use Doctrine\ORM\Cache\CollectionCacheEntry;
|
||||
use Doctrine\ORM\Cache\Lock;
|
||||
use Doctrine\ORM\Cache\Region;
|
||||
use Override;
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Traversable;
|
||||
@@ -22,8 +23,8 @@ use function strtr;
|
||||
*/
|
||||
class DefaultRegion implements Region
|
||||
{
|
||||
private const REGION_KEY_SEPARATOR = '_';
|
||||
private const REGION_PREFIX = 'DC2_REGION_';
|
||||
private const string REGION_KEY_SEPARATOR = '_';
|
||||
private const string REGION_PREFIX = 'DC2_REGION_';
|
||||
|
||||
public function __construct(
|
||||
private readonly string $name,
|
||||
@@ -32,16 +33,19 @@ class DefaultRegion implements Region
|
||||
) {
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function contains(CacheKey $key): bool
|
||||
{
|
||||
return $this->cacheItemPool->hasItem($this->getCacheEntryKey($key));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function get(CacheKey $key): CacheEntry|null
|
||||
{
|
||||
$item = $this->cacheItemPool->getItem($this->getCacheEntryKey($key));
|
||||
@@ -54,6 +58,7 @@ class DefaultRegion implements Region
|
||||
return $entry;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getMultiple(CollectionCacheEntry $collection): array|null
|
||||
{
|
||||
$keys = array_map(
|
||||
@@ -83,6 +88,7 @@ class DefaultRegion implements Region
|
||||
return $result;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function put(CacheKey $key, CacheEntry $entry, Lock|null $lock = null): bool
|
||||
{
|
||||
$item = $this->cacheItemPool
|
||||
@@ -96,11 +102,13 @@ class DefaultRegion implements Region
|
||||
return $this->cacheItemPool->save($item);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evict(CacheKey $key): bool
|
||||
{
|
||||
return $this->cacheItemPool->deleteItem($this->getCacheEntryKey($key));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evictAll(): bool
|
||||
{
|
||||
return $this->cacheItemPool->clear(self::REGION_PREFIX . $this->name);
|
||||
|
||||
@@ -11,6 +11,7 @@ use Doctrine\ORM\Cache\ConcurrentRegion;
|
||||
use Doctrine\ORM\Cache\Lock;
|
||||
use Doctrine\ORM\Cache\Region;
|
||||
use InvalidArgumentException;
|
||||
use Override;
|
||||
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
@@ -35,7 +36,7 @@ use const LOCK_EX;
|
||||
*/
|
||||
class FileLockRegion implements ConcurrentRegion
|
||||
{
|
||||
final public const LOCK_EXTENSION = 'lock';
|
||||
final public const string LOCK_EXTENSION = 'lock';
|
||||
|
||||
/**
|
||||
* @param numeric-string|int $lockLifetime
|
||||
@@ -102,11 +103,13 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return @fileatime($filename);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->region->getName();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function contains(CacheKey $key): bool
|
||||
{
|
||||
if ($this->isLocked($key)) {
|
||||
@@ -116,6 +119,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return $this->region->contains($key);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function get(CacheKey $key): CacheEntry|null
|
||||
{
|
||||
if ($this->isLocked($key)) {
|
||||
@@ -125,6 +129,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return $this->region->get($key);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getMultiple(CollectionCacheEntry $collection): array|null
|
||||
{
|
||||
if (array_filter(array_map($this->isLocked(...), $collection->identifiers))) {
|
||||
@@ -134,6 +139,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return $this->region->getMultiple($collection);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function put(CacheKey $key, CacheEntry $entry, Lock|null $lock = null): bool
|
||||
{
|
||||
if ($this->isLocked($key, $lock)) {
|
||||
@@ -143,6 +149,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return $this->region->put($key, $entry);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evict(CacheKey $key): bool
|
||||
{
|
||||
if ($this->isLocked($key)) {
|
||||
@@ -152,6 +159,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return $this->region->evict($key);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function evictAll(): bool
|
||||
{
|
||||
// The check below is necessary because on some platforms glob returns false
|
||||
@@ -165,6 +173,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return $this->region->evictAll();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function lock(CacheKey $key): Lock|null
|
||||
{
|
||||
if ($this->isLocked($key)) {
|
||||
@@ -183,6 +192,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return $lock;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function unlock(CacheKey $key, Lock $lock): bool
|
||||
{
|
||||
if ($this->isLocked($key, $lock)) {
|
||||
|
||||
@@ -7,12 +7,14 @@ namespace Doctrine\ORM\Cache\Region;
|
||||
use Doctrine\ORM\Cache\CacheKey;
|
||||
use Doctrine\ORM\Cache\TimestampCacheEntry;
|
||||
use Doctrine\ORM\Cache\TimestampRegion;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Tracks the timestamps of the most recent updates to particular keys.
|
||||
*/
|
||||
class UpdateTimestampCache extends DefaultRegion implements TimestampRegion
|
||||
{
|
||||
#[Override]
|
||||
public function update(CacheKey $key): void
|
||||
{
|
||||
$this->put($key, new TimestampCacheEntry());
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Override;
|
||||
|
||||
use function microtime;
|
||||
|
||||
class TimestampQueryCacheValidator implements QueryCacheValidator
|
||||
@@ -12,6 +14,7 @@ class TimestampQueryCacheValidator implements QueryCacheValidator
|
||||
{
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function isValid(QueryCacheKey $key, QueryCacheEntry $entry): bool
|
||||
{
|
||||
if ($this->regionUpdated($key, $entry)) {
|
||||
|
||||
@@ -17,21 +17,17 @@ use Doctrine\ORM\Mapping\EntityListenerResolver;
|
||||
use Doctrine\ORM\Mapping\NamingStrategy;
|
||||
use Doctrine\ORM\Mapping\QuoteStrategy;
|
||||
use Doctrine\ORM\Mapping\TypedFieldMapper;
|
||||
use Doctrine\ORM\Proxy\ProxyFactory;
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\Filter\SQLFilter;
|
||||
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
|
||||
use Doctrine\ORM\Repository\RepositoryFactory;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
|
||||
use LogicException;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
use function class_exists;
|
||||
use function is_a;
|
||||
use function strtolower;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
/**
|
||||
* Configuration container for all configuration options of Doctrine.
|
||||
* It combines all configuration options from DBAL & ORM.
|
||||
@@ -58,58 +54,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
return $this->identityGenerationPreferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the directory where Doctrine generates any necessary proxy class files.
|
||||
*/
|
||||
public function setProxyDir(string $dir): void
|
||||
{
|
||||
$this->attributes['proxyDir'] = $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the directory where Doctrine generates any necessary proxy class files.
|
||||
*/
|
||||
public function getProxyDir(): string|null
|
||||
{
|
||||
return $this->attributes['proxyDir'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the strategy for automatically generating proxy classes.
|
||||
*
|
||||
* @return ProxyFactory::AUTOGENERATE_*
|
||||
*/
|
||||
public function getAutoGenerateProxyClasses(): int
|
||||
{
|
||||
return $this->attributes['autoGenerateProxyClasses'] ?? ProxyFactory::AUTOGENERATE_ALWAYS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy for automatically generating proxy classes.
|
||||
*
|
||||
* @param bool|ProxyFactory::AUTOGENERATE_* $autoGenerate True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
|
||||
*/
|
||||
public function setAutoGenerateProxyClasses(bool|int $autoGenerate): void
|
||||
{
|
||||
$this->attributes['autoGenerateProxyClasses'] = (int) $autoGenerate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the namespace where proxy classes reside.
|
||||
*/
|
||||
public function getProxyNamespace(): string|null
|
||||
{
|
||||
return $this->attributes['proxyNamespace'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the namespace where proxy classes reside.
|
||||
*/
|
||||
public function setProxyNamespace(string $ns): void
|
||||
{
|
||||
$this->attributes['proxyNamespace'] = $ns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache driver implementation that is used for metadata caching.
|
||||
*
|
||||
@@ -595,62 +539,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
$this->attributes['schemaIgnoreClasses'] = $schemaIgnoreClasses;
|
||||
}
|
||||
|
||||
public function isNativeLazyObjectsEnabled(): bool
|
||||
{
|
||||
return $this->attributes['nativeLazyObjects'] ?? false;
|
||||
}
|
||||
|
||||
public function enableNativeLazyObjects(bool $nativeLazyObjects): void
|
||||
{
|
||||
if (PHP_VERSION_ID < 80400) {
|
||||
throw new LogicException('Lazy loading proxies require PHP 8.4 or higher.');
|
||||
}
|
||||
|
||||
$this->attributes['nativeLazyObjects'] = $nativeLazyObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* To be deprecated in 3.1.0
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public function isLazyGhostObjectEnabled(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** To be deprecated in 3.1.0 */
|
||||
public function setLazyGhostObjectEnabled(bool $flag): void
|
||||
{
|
||||
if (! $flag) {
|
||||
throw new LogicException(<<<'EXCEPTION'
|
||||
The lazy ghost object feature cannot be disabled anymore.
|
||||
Please remove the call to setLazyGhostObjectEnabled(false).
|
||||
EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/** To be deprecated in 3.1.0 */
|
||||
public function setRejectIdCollisionInIdentityMap(bool $flag): void
|
||||
{
|
||||
if (! $flag) {
|
||||
throw new LogicException(<<<'EXCEPTION'
|
||||
Rejecting ID collisions in the identity map cannot be disabled anymore.
|
||||
Please remove the call to setRejectIdCollisionInIdentityMap(false).
|
||||
EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be deprecated in 3.1.0
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public function isRejectIdCollisionInIdentityMapEnabled(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setEagerFetchBatchSize(int $batchSize = 100): void
|
||||
{
|
||||
$this->attributes['fetchModeSubselectBatchSize'] = $batchSize;
|
||||
|
||||
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Decorator;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\Common\EventManagerInterface;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Cache;
|
||||
@@ -24,6 +24,7 @@ use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\Persistence\ObjectManagerDecorator;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Base class for EntityManager decorators
|
||||
@@ -37,136 +38,163 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
$this->wrapped = $wrapped;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getRepository(string $className): EntityRepository
|
||||
{
|
||||
return $this->wrapped->getRepository($className);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getMetadataFactory(): ClassMetadataFactory
|
||||
{
|
||||
return $this->wrapped->getMetadataFactory();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getClassMetadata(string $className): ClassMetadata
|
||||
{
|
||||
return $this->wrapped->getClassMetadata($className);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getConnection(): Connection
|
||||
{
|
||||
return $this->wrapped->getConnection();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getExpressionBuilder(): Expr
|
||||
{
|
||||
return $this->wrapped->getExpressionBuilder();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
$this->wrapped->beginTransaction();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function wrapInTransaction(callable $func): mixed
|
||||
{
|
||||
return $this->wrapped->wrapInTransaction($func);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function commit(): void
|
||||
{
|
||||
$this->wrapped->commit();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function rollback(): void
|
||||
{
|
||||
$this->wrapped->rollback();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function createQuery(string $dql = ''): Query
|
||||
{
|
||||
return $this->wrapped->createQuery($dql);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function createNativeQuery(string $sql, ResultSetMapping $rsm): NativeQuery
|
||||
{
|
||||
return $this->wrapped->createNativeQuery($sql, $rsm);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function createQueryBuilder(): QueryBuilder
|
||||
{
|
||||
return $this->wrapped->createQueryBuilder();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getReference(string $entityName, mixed $id): object|null
|
||||
{
|
||||
return $this->wrapped->getReference($entityName, $id);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function close(): void
|
||||
{
|
||||
$this->wrapped->close();
|
||||
}
|
||||
|
||||
public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|int|null $lockVersion = null): void
|
||||
#[Override]
|
||||
public function lock(object $entity, LockMode $lockMode, DateTimeInterface|int|null $lockVersion = null): void
|
||||
{
|
||||
$this->wrapped->lock($entity, $lockMode, $lockVersion);
|
||||
}
|
||||
|
||||
public function find(string $className, mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null
|
||||
#[Override]
|
||||
public function find(string $className, mixed $id, LockMode|null $lockMode = null, int|null $lockVersion = null): object|null
|
||||
{
|
||||
return $this->wrapped->find($className, $id, $lockMode, $lockVersion);
|
||||
}
|
||||
|
||||
public function refresh(object $object, LockMode|int|null $lockMode = null): void
|
||||
#[Override]
|
||||
public function refresh(object $object, LockMode|null $lockMode = null): void
|
||||
{
|
||||
$this->wrapped->refresh($object, $lockMode);
|
||||
}
|
||||
|
||||
public function getEventManager(): EventManager
|
||||
#[Override]
|
||||
public function getEventManager(): EventManagerInterface
|
||||
{
|
||||
return $this->wrapped->getEventManager();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getConfiguration(): Configuration
|
||||
{
|
||||
return $this->wrapped->getConfiguration();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function isOpen(): bool
|
||||
{
|
||||
return $this->wrapped->isOpen();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getUnitOfWork(): UnitOfWork
|
||||
{
|
||||
return $this->wrapped->getUnitOfWork();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function newHydrator(string|int $hydrationMode): AbstractHydrator
|
||||
{
|
||||
return $this->wrapped->newHydrator($hydrationMode);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getProxyFactory(): ProxyFactory
|
||||
{
|
||||
return $this->wrapped->getProxyFactory();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getFilters(): FilterCollection
|
||||
{
|
||||
return $this->wrapped->getFilters();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function isFiltersStateClean(): bool
|
||||
{
|
||||
return $this->wrapped->isFiltersStateClean();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function hasFilters(): bool
|
||||
{
|
||||
return $this->wrapped->hasFilters();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getCache(): Cache|null
|
||||
{
|
||||
return $this->wrapped->getCache();
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Doctrine\ORM;
|
||||
use BackedEnum;
|
||||
use DateTimeInterface;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\Common\EventManagerInterface;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Exception\EntityManagerClosed;
|
||||
@@ -18,18 +19,17 @@ use Doctrine\ORM\Exception\UnrecognizedIdentifierFields;
|
||||
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
|
||||
use Doctrine\ORM\Proxy\ProxyFactory;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\Query\FilterCollection;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Repository\RepositoryFactory;
|
||||
use Override;
|
||||
|
||||
use function array_keys;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function ltrim;
|
||||
use function method_exists;
|
||||
|
||||
/**
|
||||
* The EntityManager is the central access point to ORM functionality.
|
||||
@@ -43,7 +43,7 @@ use function method_exists;
|
||||
*
|
||||
* $paths = ['/path/to/entity/mapping/files'];
|
||||
*
|
||||
* $config = ORMSetup::createAttributeMetadataConfiguration($paths);
|
||||
* $config = ORMSetup::createAttributeMetadataConfig($paths);
|
||||
* $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'memory' => true], $config);
|
||||
* $entityManager = new EntityManager($connection, $config);
|
||||
*
|
||||
@@ -72,7 +72,7 @@ class EntityManager implements EntityManagerInterface
|
||||
/**
|
||||
* The event manager that is the central point of the event system.
|
||||
*/
|
||||
private EventManager $eventManager;
|
||||
private EventManagerInterface $eventManager;
|
||||
|
||||
/**
|
||||
* The proxy factory used to create dynamic proxies.
|
||||
@@ -113,17 +113,13 @@ class EntityManager implements EntityManagerInterface
|
||||
public function __construct(
|
||||
private Connection $conn,
|
||||
private Configuration $config,
|
||||
EventManager|null $eventManager = null,
|
||||
EventManagerInterface|null $eventManager = null,
|
||||
) {
|
||||
if (! $config->getMetadataDriverImpl()) {
|
||||
throw MissingMappingDriverImplementation::create();
|
||||
}
|
||||
|
||||
$this->eventManager = $eventManager
|
||||
?? (method_exists($conn, 'getEventManager')
|
||||
? $conn->getEventManager()
|
||||
: new EventManager()
|
||||
);
|
||||
$this->eventManager = $eventManager ?? new EventManager();
|
||||
|
||||
$metadataFactoryClassName = $config->getClassMetadataFactoryName();
|
||||
|
||||
@@ -134,12 +130,7 @@ class EntityManager implements EntityManagerInterface
|
||||
|
||||
$this->repositoryFactory = $config->getRepositoryFactory();
|
||||
$this->unitOfWork = new UnitOfWork($this);
|
||||
$this->proxyFactory = new ProxyFactory(
|
||||
$this,
|
||||
$config->getProxyDir(),
|
||||
$config->getProxyNamespace(),
|
||||
$config->getAutoGenerateProxyClasses(),
|
||||
);
|
||||
$this->proxyFactory = new ProxyFactory($this);
|
||||
|
||||
if ($config->isSecondLevelCacheEnabled()) {
|
||||
$cacheConfig = $config->getSecondLevelCacheConfiguration();
|
||||
@@ -148,31 +139,37 @@ class EntityManager implements EntityManagerInterface
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getConnection(): Connection
|
||||
{
|
||||
return $this->conn;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getMetadataFactory(): ClassMetadataFactory
|
||||
{
|
||||
return $this->metadataFactory;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getExpressionBuilder(): Expr
|
||||
{
|
||||
return $this->expressionBuilder ??= new Expr();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
$this->conn->beginTransaction();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getCache(): Cache|null
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function wrapInTransaction(callable $func): mixed
|
||||
{
|
||||
$this->conn->beginTransaction();
|
||||
@@ -198,11 +195,13 @@ class EntityManager implements EntityManagerInterface
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function commit(): void
|
||||
{
|
||||
$this->conn->commit();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function rollback(): void
|
||||
{
|
||||
$this->conn->rollBack();
|
||||
@@ -215,11 +214,13 @@ class EntityManager implements EntityManagerInterface
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function getClassMetadata(string $className): Mapping\ClassMetadata
|
||||
{
|
||||
return $this->metadataFactory->getMetadataFor($className);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function createQuery(string $dql = ''): Query
|
||||
{
|
||||
$query = new Query($this);
|
||||
@@ -231,6 +232,7 @@ class EntityManager implements EntityManagerInterface
|
||||
return $query;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function createNativeQuery(string $sql, ResultSetMapping $rsm): NativeQuery
|
||||
{
|
||||
$query = new NativeQuery($this);
|
||||
@@ -241,6 +243,7 @@ class EntityManager implements EntityManagerInterface
|
||||
return $query;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function createQueryBuilder(): QueryBuilder
|
||||
{
|
||||
return new QueryBuilder($this);
|
||||
@@ -258,6 +261,7 @@ class EntityManager implements EntityManagerInterface
|
||||
* makes use of optimistic locking fails.
|
||||
* @throws ORMException
|
||||
*/
|
||||
#[Override]
|
||||
public function flush(): void
|
||||
{
|
||||
$this->errorIfClosed();
|
||||
@@ -267,7 +271,8 @@ class EntityManager implements EntityManagerInterface
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($className, mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null
|
||||
#[Override]
|
||||
public function find($className, mixed $id, LockMode|null $lockMode = null, int|null $lockVersion = null): object|null
|
||||
{
|
||||
$class = $this->metadataFactory->getMetadataFor(ltrim($className, '\\'));
|
||||
|
||||
@@ -285,7 +290,7 @@ class EntityManager implements EntityManagerInterface
|
||||
|
||||
foreach ($id as $i => $value) {
|
||||
if (is_object($value)) {
|
||||
$className = DefaultProxyClassNameResolver::getClass($value);
|
||||
$className = $value::class;
|
||||
if ($this->metadataFactory->hasMetadataFor($className)) {
|
||||
$id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
|
||||
|
||||
@@ -363,6 +368,7 @@ class EntityManager implements EntityManagerInterface
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getReference(string $entityName, mixed $id): object|null
|
||||
{
|
||||
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
|
||||
@@ -408,11 +414,13 @@ class EntityManager implements EntityManagerInterface
|
||||
* Clears the EntityManager. All entities that are currently managed
|
||||
* by this EntityManager become detached.
|
||||
*/
|
||||
#[Override]
|
||||
public function clear(): void
|
||||
{
|
||||
$this->unitOfWork->clear();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function close(): void
|
||||
{
|
||||
$this->clear();
|
||||
@@ -432,6 +440,7 @@ class EntityManager implements EntityManagerInterface
|
||||
* @throws ORMInvalidArgumentException
|
||||
* @throws ORMException
|
||||
*/
|
||||
#[Override]
|
||||
public function persist(object $object): void
|
||||
{
|
||||
$this->errorIfClosed();
|
||||
@@ -448,6 +457,7 @@ class EntityManager implements EntityManagerInterface
|
||||
* @throws ORMInvalidArgumentException
|
||||
* @throws ORMException
|
||||
*/
|
||||
#[Override]
|
||||
public function remove(object $object): void
|
||||
{
|
||||
$this->errorIfClosed();
|
||||
@@ -455,7 +465,8 @@ class EntityManager implements EntityManagerInterface
|
||||
$this->unitOfWork->remove($object);
|
||||
}
|
||||
|
||||
public function refresh(object $object, LockMode|int|null $lockMode = null): void
|
||||
#[Override]
|
||||
public function refresh(object $object, LockMode|null $lockMode = null): void
|
||||
{
|
||||
$this->errorIfClosed();
|
||||
|
||||
@@ -471,12 +482,14 @@ class EntityManager implements EntityManagerInterface
|
||||
*
|
||||
* @throws ORMInvalidArgumentException
|
||||
*/
|
||||
#[Override]
|
||||
public function detach(object $object): void
|
||||
{
|
||||
$this->unitOfWork->detach($object);
|
||||
}
|
||||
|
||||
public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|int|null $lockVersion = null): void
|
||||
#[Override]
|
||||
public function lock(object $entity, LockMode $lockMode, DateTimeInterface|int|null $lockVersion = null): void
|
||||
{
|
||||
$this->unitOfWork->lock($entity, $lockMode, $lockVersion);
|
||||
}
|
||||
@@ -490,6 +503,7 @@ class EntityManager implements EntityManagerInterface
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
#[Override]
|
||||
public function getRepository(string $className): EntityRepository
|
||||
{
|
||||
return $this->repositoryFactory->getRepository($this, $className);
|
||||
@@ -500,6 +514,7 @@ class EntityManager implements EntityManagerInterface
|
||||
*
|
||||
* @return bool TRUE if this EntityManager currently manages the given entity, FALSE otherwise.
|
||||
*/
|
||||
#[Override]
|
||||
public function contains(object $object): bool
|
||||
{
|
||||
return $this->unitOfWork->isScheduledForInsert($object)
|
||||
@@ -507,11 +522,13 @@ class EntityManager implements EntityManagerInterface
|
||||
&& ! $this->unitOfWork->isScheduledForDelete($object);
|
||||
}
|
||||
|
||||
public function getEventManager(): EventManager
|
||||
#[Override]
|
||||
public function getEventManager(): EventManagerInterface
|
||||
{
|
||||
return $this->eventManager;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getConfiguration(): Configuration
|
||||
{
|
||||
return $this->config;
|
||||
@@ -529,16 +546,19 @@ class EntityManager implements EntityManagerInterface
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function isOpen(): bool
|
||||
{
|
||||
return ! $this->closed;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getUnitOfWork(): UnitOfWork
|
||||
{
|
||||
return $this->unitOfWork;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function newHydrator(string|int $hydrationMode): AbstractHydrator
|
||||
{
|
||||
return match ($hydrationMode) {
|
||||
@@ -552,11 +572,13 @@ class EntityManager implements EntityManagerInterface
|
||||
};
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getProxyFactory(): ProxyFactory
|
||||
{
|
||||
return $this->proxyFactory;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function initializeObject(object $obj): void
|
||||
{
|
||||
$this->unitOfWork->initializeObject($obj);
|
||||
@@ -565,33 +587,35 @@ class EntityManager implements EntityManagerInterface
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function isUninitializedObject($value): bool
|
||||
{
|
||||
return $this->unitOfWork->isUninitializedObject($value);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getFilters(): FilterCollection
|
||||
{
|
||||
return $this->filterCollection ??= new FilterCollection($this);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function isFiltersStateClean(): bool
|
||||
{
|
||||
return $this->filterCollection === null || $this->filterCollection->isClean();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function hasFilters(): bool
|
||||
{
|
||||
return $this->filterCollection !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param LockMode::* $lockMode
|
||||
*
|
||||
* @throws OptimisticLockException
|
||||
* @throws TransactionRequiredException
|
||||
*/
|
||||
private function checkLockRequirements(LockMode|int $lockMode, ClassMetadata $class): void
|
||||
private function checkLockRequirements(LockMode $lockMode, ClassMetadata $class): void
|
||||
{
|
||||
switch ($lockMode) {
|
||||
case LockMode::OPTIMISTIC:
|
||||
|
||||
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\Common\EventManagerInterface;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\Exception\ORMException;
|
||||
@@ -16,6 +16,7 @@ use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\Query\FilterCollection;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use Override;
|
||||
|
||||
interface EntityManagerInterface extends ObjectManager
|
||||
{
|
||||
@@ -28,6 +29,7 @@ interface EntityManagerInterface extends ObjectManager
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
#[Override]
|
||||
public function getRepository(string $className): EntityRepository;
|
||||
|
||||
/**
|
||||
@@ -40,6 +42,7 @@ interface EntityManagerInterface extends ObjectManager
|
||||
*/
|
||||
public function getConnection(): Connection;
|
||||
|
||||
#[Override]
|
||||
public function getMetadataFactory(): ClassMetadataFactory;
|
||||
|
||||
/**
|
||||
@@ -110,15 +113,13 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* Finds an Entity by its identifier.
|
||||
*
|
||||
* @param string $className The class name of the entity to find.
|
||||
* @param mixed $id The identity of the entity to find.
|
||||
* @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.
|
||||
* @param int|null $lockVersion The version of the entity to find when using
|
||||
* optimistic locking.
|
||||
* @param string $className The class name of the entity to find.
|
||||
* @param mixed $id The identity of the entity to find.
|
||||
* @param LockMode|null $lockMode The lock mode or NULL if no specific lock mode
|
||||
* should be used during the search.
|
||||
* @param int|null $lockVersion The version of the entity to find when using
|
||||
* optimistic locking.
|
||||
* @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.
|
||||
* @phpstan-return T|null
|
||||
@@ -130,22 +131,22 @@ interface EntityManagerInterface extends ObjectManager
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public function find(string $className, mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null;
|
||||
#[Override]
|
||||
public function find(string $className, mixed $id, LockMode|null $lockMode = null, int|null $lockVersion = null): object|null;
|
||||
|
||||
/**
|
||||
* Refreshes the persistent state of an object from the database,
|
||||
* overriding any local changes that have not yet been persisted.
|
||||
*
|
||||
* @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.
|
||||
* @phpstan-param LockMode::*|null $lockMode
|
||||
* @param LockMode|null $lockMode The lock mode or NULL if no specific lock mode
|
||||
* should be used during the search.
|
||||
*
|
||||
* @throws ORMInvalidArgumentException
|
||||
* @throws ORMException
|
||||
* @throws TransactionRequiredException
|
||||
*/
|
||||
public function refresh(object $object, LockMode|int|null $lockMode = null): void;
|
||||
#[Override]
|
||||
public function refresh(object $object, LockMode|null $lockMode = null): void;
|
||||
|
||||
/**
|
||||
* Gets a reference to the entity identified by the given type and identifier
|
||||
@@ -172,17 +173,15 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* Acquire a lock on the given entity.
|
||||
*
|
||||
* @phpstan-param LockMode::* $lockMode
|
||||
*
|
||||
* @throws OptimisticLockException
|
||||
* @throws PessimisticLockException
|
||||
*/
|
||||
public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|int|null $lockVersion = null): void;
|
||||
public function lock(object $entity, LockMode $lockMode, DateTimeInterface|int|null $lockVersion = null): void;
|
||||
|
||||
/**
|
||||
* Gets the EventManager used by the EntityManager.
|
||||
* Gets the EventManagerInterface used by the EntityManager.
|
||||
*/
|
||||
public function getEventManager(): EventManager;
|
||||
public function getEventManager(): EventManagerInterface;
|
||||
|
||||
/**
|
||||
* Gets the Configuration used by the EntityManager.
|
||||
@@ -237,5 +236,6 @@ interface EntityManagerInterface extends ObjectManager
|
||||
*
|
||||
* @phpstan-template T of object
|
||||
*/
|
||||
#[Override]
|
||||
public function getClassMetadata(string $className): Mapping\ClassMetadata;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
use Doctrine\ORM\Repository\Exception\InvalidMagicMethodCall;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Override;
|
||||
|
||||
use function array_slice;
|
||||
use function lcfirst;
|
||||
@@ -73,15 +74,14 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
/**
|
||||
* Finds an entity by its primary key / identifier.
|
||||
*
|
||||
* @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.
|
||||
* @phpstan-param LockMode::*|null $lockMode
|
||||
* @param LockMode|null $lockMode The lock mode or NULL if no specific lock mode
|
||||
* should be used during the search.
|
||||
*
|
||||
* @return object|null The entity instance or NULL if the entity can not be found.
|
||||
* @phpstan-return ?T
|
||||
*/
|
||||
public function find(mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null
|
||||
#[Override]
|
||||
public function find(mixed $id, LockMode|null $lockMode = null, int|null $lockVersion = null): object|null
|
||||
{
|
||||
return $this->em->find($this->entityName, $id, $lockMode, $lockVersion);
|
||||
}
|
||||
@@ -91,6 +91,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
*
|
||||
* @phpstan-return list<T> The entities.
|
||||
*/
|
||||
#[Override]
|
||||
public function findAll(): array
|
||||
{
|
||||
return $this->findBy([]);
|
||||
@@ -103,6 +104,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
*
|
||||
* @phpstan-return list<T>
|
||||
*/
|
||||
#[Override]
|
||||
public function findBy(array $criteria, array|null $orderBy = null, int|null $limit = null, int|null $offset = null): array
|
||||
{
|
||||
$persister = $this->em->getUnitOfWork()->getEntityPersister($this->entityName);
|
||||
@@ -118,6 +120,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
*
|
||||
* @phpstan-return T|null
|
||||
*/
|
||||
#[Override]
|
||||
public function findOneBy(array $criteria, array|null $orderBy = null): object|null
|
||||
{
|
||||
$persister = $this->em->getUnitOfWork()->getEntityPersister($this->entityName);
|
||||
@@ -175,6 +178,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
return $this->entityName;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getClassName(): string
|
||||
{
|
||||
return $this->getEntityName();
|
||||
@@ -197,6 +201,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
*
|
||||
* @phpstan-return AbstractLazyCollection<int, T>&Selectable<int, T>
|
||||
*/
|
||||
#[Override]
|
||||
public function matching(Criteria $criteria): AbstractLazyCollection&Selectable
|
||||
{
|
||||
$persister = $this->em->getUnitOfWork()->getEntityPersister($this->entityName);
|
||||
|
||||
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\Common\EventDispatcher;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\EntityListenerResolver;
|
||||
@@ -15,21 +15,21 @@ use Doctrine\ORM\Mapping\EntityListenerResolver;
|
||||
*/
|
||||
class ListenersInvoker
|
||||
{
|
||||
final public const INVOKE_NONE = 0;
|
||||
final public const INVOKE_LISTENERS = 1;
|
||||
final public const INVOKE_CALLBACKS = 2;
|
||||
final public const INVOKE_MANAGER = 4;
|
||||
final public const int INVOKE_NONE = 0;
|
||||
final public const int INVOKE_LISTENERS = 1;
|
||||
final public const int INVOKE_CALLBACKS = 2;
|
||||
final public const int INVOKE_MANAGER = 4;
|
||||
|
||||
/** The Entity listener resolver. */
|
||||
private readonly EntityListenerResolver $resolver;
|
||||
|
||||
/** The EventManager used for dispatching events. */
|
||||
private readonly EventManager $eventManager;
|
||||
/** The EventDispatcher used for dispatching events. */
|
||||
private readonly EventDispatcher $eventDispatcher;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->eventManager = $em->getEventManager();
|
||||
$this->resolver = $em->getConfiguration()->getEntityListenerResolver();
|
||||
$this->eventDispatcher = $em->getEventManager();
|
||||
$this->resolver = $em->getConfiguration()->getEntityListenerResolver();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ class ListenersInvoker
|
||||
$invoke |= self::INVOKE_LISTENERS;
|
||||
}
|
||||
|
||||
if ($this->eventManager->hasListeners($eventName)) {
|
||||
if ($this->eventDispatcher->hasListeners($eventName)) {
|
||||
$invoke |= self::INVOKE_MANAGER;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ class ListenersInvoker
|
||||
}
|
||||
|
||||
if ($invoke & self::INVOKE_MANAGER) {
|
||||
$this->eventManager->dispatchEvent($eventName, $event);
|
||||
$this->eventDispatcher->dispatchEvent($eventName, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ final class Events
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*/
|
||||
public const preRemove = 'preRemove';
|
||||
final public const string preRemove = 'preRemove';
|
||||
|
||||
/**
|
||||
* The postRemove event occurs for an entity after the entity has
|
||||
@@ -32,7 +32,7 @@ final class Events
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*/
|
||||
public const postRemove = 'postRemove';
|
||||
final public const string postRemove = 'postRemove';
|
||||
|
||||
/**
|
||||
* The prePersist event occurs for a given entity before the respective
|
||||
@@ -40,7 +40,7 @@ final class Events
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*/
|
||||
public const prePersist = 'prePersist';
|
||||
final public const string prePersist = 'prePersist';
|
||||
|
||||
/**
|
||||
* The postPersist event occurs for an entity after the entity has
|
||||
@@ -49,7 +49,7 @@ final class Events
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*/
|
||||
public const postPersist = 'postPersist';
|
||||
final public const string postPersist = 'postPersist';
|
||||
|
||||
/**
|
||||
* The preUpdate event occurs before the database update operations to
|
||||
@@ -57,7 +57,7 @@ final class Events
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*/
|
||||
public const preUpdate = 'preUpdate';
|
||||
final public const string preUpdate = 'preUpdate';
|
||||
|
||||
/**
|
||||
* The postUpdate event occurs after the database update operations to
|
||||
@@ -65,7 +65,7 @@ final class Events
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*/
|
||||
public const postUpdate = 'postUpdate';
|
||||
final public const string postUpdate = 'postUpdate';
|
||||
|
||||
/**
|
||||
* The postLoad event occurs for an entity after the entity has been loaded
|
||||
@@ -78,26 +78,26 @@ final class Events
|
||||
*
|
||||
* This is an entity lifecycle event.
|
||||
*/
|
||||
public const postLoad = 'postLoad';
|
||||
final public const string postLoad = 'postLoad';
|
||||
|
||||
/**
|
||||
* The loadClassMetadata event occurs after the mapping metadata for a class
|
||||
* has been loaded from a mapping source (attributes/xml).
|
||||
*/
|
||||
public const loadClassMetadata = 'loadClassMetadata';
|
||||
final public const string loadClassMetadata = 'loadClassMetadata';
|
||||
|
||||
/**
|
||||
* The onClassMetadataNotFound event occurs whenever loading metadata for a class
|
||||
* failed.
|
||||
*/
|
||||
public const onClassMetadataNotFound = 'onClassMetadataNotFound';
|
||||
final public const string onClassMetadataNotFound = 'onClassMetadataNotFound';
|
||||
|
||||
/**
|
||||
* The preFlush event occurs when the EntityManager#flush() operation is invoked,
|
||||
* but before any changes to managed entities have been calculated. This event is
|
||||
* always raised right after EntityManager#flush() call.
|
||||
*/
|
||||
public const preFlush = 'preFlush';
|
||||
final public const string preFlush = 'preFlush';
|
||||
|
||||
/**
|
||||
* The onFlush event occurs when the EntityManager#flush() operation is invoked,
|
||||
@@ -105,7 +105,7 @@ final class Events
|
||||
* actual database operations are executed. The event is only raised if there is
|
||||
* actually something to do for the underlying UnitOfWork.
|
||||
*/
|
||||
public const onFlush = 'onFlush';
|
||||
final public const string onFlush = 'onFlush';
|
||||
|
||||
/**
|
||||
* The postFlush event occurs when the EntityManager#flush() operation is invoked and
|
||||
@@ -113,11 +113,11 @@ final class Events
|
||||
* 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';
|
||||
final public const string postFlush = 'postFlush';
|
||||
|
||||
/**
|
||||
* The onClear event occurs when the EntityManager#clear() operation is invoked,
|
||||
* after all references to entities have been removed from the unit of work.
|
||||
*/
|
||||
public const onClear = 'onClear';
|
||||
final public const string onClear = 'onClear';
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use function sprintf;
|
||||
|
||||
final class MultipleSelectorsFoundException extends LogicException implements ORMException
|
||||
{
|
||||
public const MULTIPLE_SELECTORS_FOUND_EXCEPTION = 'Multiple selectors found: %s. Please select only one.';
|
||||
final public const string MULTIPLE_SELECTORS_FOUND_EXCEPTION = 'Multiple selectors found: %s. Please select only one.';
|
||||
|
||||
/** @param string[] $selectors */
|
||||
public static function create(array $selectors): self
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Exception;
|
||||
|
||||
use LogicException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/** @deprecated */
|
||||
final class NotSupported extends LogicException implements ORMException
|
||||
{
|
||||
public static function create(): self
|
||||
{
|
||||
return new self('This behaviour is (currently) not supported by Doctrine 2');
|
||||
}
|
||||
|
||||
public static function createForDbal3(string $context): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
<<<'EXCEPTION'
|
||||
Context: %s
|
||||
Problem: Feature was deprecated in doctrine/dbal 2.x and is not supported by installed doctrine/dbal:3.x
|
||||
Solution: See the doctrine/deprecations logs for new alternative approaches.
|
||||
EXCEPTION
|
||||
,
|
||||
$context,
|
||||
));
|
||||
}
|
||||
|
||||
public static function createForPersistence3(string $context): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
<<<'EXCEPTION'
|
||||
Context: %s
|
||||
Problem: Feature was deprecated in doctrine/persistence 2.x and is not supported by installed doctrine/persistence:3.x
|
||||
Solution: See the doctrine/deprecations logs for new alternative approaches.
|
||||
EXCEPTION
|
||||
,
|
||||
$context,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ namespace Doctrine\ORM\Id;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Exception\EntityMissingAssignedId;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Special generator for application-assigned identifiers (doesn't really generate anything).
|
||||
@@ -19,6 +20,7 @@ class AssignedGenerator extends AbstractIdGenerator
|
||||
*
|
||||
* @throws EntityMissingAssignedId
|
||||
*/
|
||||
#[Override]
|
||||
public function generateId(EntityManagerInterface $em, object|null $entity): array
|
||||
{
|
||||
$class = $em->getClassMetadata($entity::class);
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Id generator that obtains IDs from special "identity" columns. These are columns
|
||||
@@ -13,11 +14,13 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
*/
|
||||
class BigIntegerIdentityGenerator extends AbstractIdGenerator
|
||||
{
|
||||
#[Override]
|
||||
public function generateId(EntityManagerInterface $em, object|null $entity): string
|
||||
{
|
||||
return (string) $em->getConnection()->lastInsertId();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function isPostInsertGenerator(): bool
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Id generator that obtains IDs from special "identity" columns. These are columns
|
||||
@@ -13,11 +14,13 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
*/
|
||||
class IdentityGenerator extends AbstractIdGenerator
|
||||
{
|
||||
#[Override]
|
||||
public function generateId(EntityManagerInterface $em, object|null $entity): int
|
||||
{
|
||||
return (int) $em->getConnection()->lastInsertId();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function isPostInsertGenerator(): bool
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -5,17 +5,13 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Serializable;
|
||||
|
||||
use function serialize;
|
||||
use function unserialize;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Represents an ID generator that uses a database sequence.
|
||||
*/
|
||||
class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
class SequenceGenerator extends AbstractIdGenerator
|
||||
{
|
||||
private int $nextValue = 0;
|
||||
private int|null $maxValue = null;
|
||||
@@ -32,6 +28,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
) {
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function generateId(EntityManagerInterface $em, object|null $entity): int
|
||||
{
|
||||
if ($this->maxValue === null || $this->nextValue === $this->maxValue) {
|
||||
@@ -66,20 +63,6 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
return $this->nextValue;
|
||||
}
|
||||
|
||||
/** @deprecated without replacement. */
|
||||
final public function serialize(): string
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11468',
|
||||
'%s() is deprecated, use __serialize() instead. %s won\'t implement the Serializable interface anymore in ORM 4.',
|
||||
__METHOD__,
|
||||
self::class,
|
||||
);
|
||||
|
||||
return serialize($this->__serialize());
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function __serialize(): array
|
||||
{
|
||||
@@ -89,20 +72,6 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
];
|
||||
}
|
||||
|
||||
/** @deprecated without replacement. */
|
||||
final public function unserialize(string $serialized): void
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11468',
|
||||
'%s() is deprecated, use __unserialize() instead. %s won\'t implement the Serializable interface anymore in ORM 4.',
|
||||
__METHOD__,
|
||||
self::class,
|
||||
);
|
||||
|
||||
$this->__unserialize(unserialize($serialized));
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
|
||||
@@ -17,15 +17,18 @@ use Doctrine\ORM\UnitOfWork;
|
||||
use Generator;
|
||||
use LogicException;
|
||||
use ReflectionClass;
|
||||
use ReflectionEnum;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use function current;
|
||||
use function end;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function ksort;
|
||||
|
||||
/**
|
||||
@@ -126,8 +129,10 @@ abstract class AbstractHydrator
|
||||
} else {
|
||||
yield from $result;
|
||||
}
|
||||
} else {
|
||||
} elseif (is_object(current($result))) {
|
||||
yield $result;
|
||||
} else {
|
||||
yield array_merge(...$result);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -593,13 +598,18 @@ abstract class AbstractHydrator
|
||||
*/
|
||||
final protected function buildEnum(mixed $value, string $enumType): BackedEnum|array
|
||||
{
|
||||
$reflection = new ReflectionEnum($enumType);
|
||||
$isIntBacked = $reflection->isBacked() && $reflection->getBackingType()->getName() === 'int';
|
||||
|
||||
if (is_array($value)) {
|
||||
return array_map(
|
||||
static fn ($value) => $enumType::from($value),
|
||||
static fn ($value) => $enumType::from($isIntBacked ? (int) $value : $value),
|
||||
$value,
|
||||
);
|
||||
}
|
||||
|
||||
$value = $isIntBacked ? (int) $value : $value;
|
||||
|
||||
return $enumType::from($value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use Override;
|
||||
|
||||
use function array_key_last;
|
||||
use function count;
|
||||
use function is_array;
|
||||
@@ -32,6 +34,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
|
||||
private int $resultCounter = 0;
|
||||
|
||||
#[Override]
|
||||
protected function prepare(): void
|
||||
{
|
||||
$this->isSimpleQuery = count($this->resultSetMapping()->aliasMap) <= 1;
|
||||
@@ -46,6 +49,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
protected function hydrateAllData(): array
|
||||
{
|
||||
$result = [];
|
||||
@@ -60,6 +64,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
protected function hydrateRowData(array $row, array &$result): void
|
||||
{
|
||||
// 1) Initialize
|
||||
|
||||
@@ -10,6 +10,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Override;
|
||||
|
||||
use function array_fill_keys;
|
||||
use function array_keys;
|
||||
@@ -51,6 +52,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
/** @var mixed[] */
|
||||
private array $existingCollections = [];
|
||||
|
||||
#[Override]
|
||||
protected function prepare(): void
|
||||
{
|
||||
if (! isset($this->hints[UnitOfWork::HINT_DEFEREAGERLOAD])) {
|
||||
@@ -108,6 +110,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
}
|
||||
|
||||
#[Override]
|
||||
protected function cleanup(): void
|
||||
{
|
||||
$eagerLoad = isset($this->hints[UnitOfWork::HINT_DEFEREAGERLOAD]) && $this->hints[UnitOfWork::HINT_DEFEREAGERLOAD] === true;
|
||||
@@ -127,6 +130,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$this->uow->hydrationComplete();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
protected function cleanupAfterRowIteration(): void
|
||||
{
|
||||
$this->identifierMap =
|
||||
@@ -139,6 +143,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
protected function hydrateAllData(): array
|
||||
{
|
||||
$result = [];
|
||||
@@ -318,6 +323,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* @param mixed[] $row The data of the row to process.
|
||||
* @param mixed[] $result The result array to fill.
|
||||
*/
|
||||
#[Override]
|
||||
protected function hydrateRowData(array $row, array &$result): void
|
||||
{
|
||||
// Initialize
|
||||
@@ -574,6 +580,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/** @param mixed[] $data pre-hydrated SQL Result Row. */
|
||||
#[Override]
|
||||
protected function hydrateNestedEntity(array $data, string $dqlAlias): mixed
|
||||
{
|
||||
if (isset($this->resultSetMapping()->nestedEntities[$dqlAlias])) {
|
||||
@@ -587,6 +594,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* When executed in a hydrate() loop we may have to clear internal state to
|
||||
* decrease memory consumption.
|
||||
*/
|
||||
#[Override]
|
||||
public function onClear(mixed $eventArgs): void
|
||||
{
|
||||
parent::onClear($eventArgs);
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use Doctrine\DBAL\Driver\Exception;
|
||||
use Doctrine\ORM\Exception\MultipleSelectorsFoundException;
|
||||
use Override;
|
||||
|
||||
use function array_column;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
@@ -21,14 +21,13 @@ final class ScalarColumnHydrator extends AbstractHydrator
|
||||
* @throws MultipleSelectorsFoundException
|
||||
* @throws Exception
|
||||
*/
|
||||
#[Override]
|
||||
protected function hydrateAllData(): array
|
||||
{
|
||||
if (count($this->resultSetMapping()->fieldMappings) > 1) {
|
||||
throw MultipleSelectorsFoundException::create($this->resultSetMapping()->fieldMappings);
|
||||
}
|
||||
|
||||
$result = $this->statement()->fetchAllNumeric();
|
||||
|
||||
return array_column($result, 0);
|
||||
return $this->statement()->fetchFirstColumn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Hydrator that produces flat, rectangular results of scalar data.
|
||||
* The created result is almost the same as a regular SQL result set, except
|
||||
@@ -14,6 +16,7 @@ class ScalarHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
protected function hydrateAllData(): array
|
||||
{
|
||||
$result = [];
|
||||
@@ -28,6 +31,7 @@ class ScalarHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
protected function hydrateRowData(array $row, array &$result): void
|
||||
{
|
||||
$result[] = $this->gatherScalarRowData($row);
|
||||
|
||||
@@ -9,6 +9,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\ORM\Query;
|
||||
use Exception;
|
||||
use Override;
|
||||
use RuntimeException;
|
||||
use ValueError;
|
||||
|
||||
@@ -28,6 +29,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
|
||||
private ClassMetadata|null $class = null;
|
||||
|
||||
#[Override]
|
||||
protected function prepare(): void
|
||||
{
|
||||
if (count($this->resultSetMapping()->aliasMap) !== 1) {
|
||||
@@ -41,6 +43,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
$this->class = $this->getClassMetadata(reset($this->resultSetMapping()->aliasMap));
|
||||
}
|
||||
|
||||
#[Override]
|
||||
protected function cleanup(): void
|
||||
{
|
||||
parent::cleanup();
|
||||
@@ -52,6 +55,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
protected function hydrateAllData(): array
|
||||
{
|
||||
$result = [];
|
||||
@@ -68,6 +72,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
protected function hydrateRowData(array $row, array &$result): void
|
||||
{
|
||||
assert($this->class !== null);
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Doctrine\ORM\Internal\Hydration;
|
||||
|
||||
use Doctrine\ORM\NonUniqueResultException;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Override;
|
||||
|
||||
use function array_shift;
|
||||
use function count;
|
||||
@@ -16,6 +17,7 @@ use function key;
|
||||
*/
|
||||
class SingleScalarHydrator extends AbstractHydrator
|
||||
{
|
||||
#[Override]
|
||||
protected function hydrateAllData(): mixed
|
||||
{
|
||||
$data = $this->statement()->fetchAllAssociative();
|
||||
|
||||
@@ -25,9 +25,9 @@ use function spl_object_id;
|
||||
*/
|
||||
final class StronglyConnectedComponents
|
||||
{
|
||||
private const NOT_VISITED = 1;
|
||||
private const IN_PROGRESS = 2;
|
||||
private const VISITED = 3;
|
||||
private const int NOT_VISITED = 1;
|
||||
private const int IN_PROGRESS = 2;
|
||||
private const int VISITED = 3;
|
||||
|
||||
/**
|
||||
* Array of all nodes, indexed by object ids.
|
||||
|
||||
@@ -20,9 +20,9 @@ use function spl_object_id;
|
||||
*/
|
||||
final class TopologicalSort
|
||||
{
|
||||
private const NOT_VISITED = 1;
|
||||
private const IN_PROGRESS = 2;
|
||||
private const VISITED = 3;
|
||||
private const int NOT_VISITED = 1;
|
||||
private const int IN_PROGRESS = 2;
|
||||
private const int VISITED = 3;
|
||||
|
||||
/**
|
||||
* Array of all nodes, indexed by object ids.
|
||||
|
||||
79
src/Internal/UnitOfWork/InsertBatch.php
Normal file
79
src/Internal/UnitOfWork/InsertBatch.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\UnitOfWork;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Id\AssignedGenerator;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* An {@see InsertBatch} represents a set of entities that are safe to be batched
|
||||
* together in a single query.
|
||||
*
|
||||
* These entities are only those that have all fields already assigned, including the
|
||||
* identifier field(s).
|
||||
*
|
||||
* This data structure only exists for internal {@see UnitOfWork} optimisations, and
|
||||
* should not be relied upon outside the ORM.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @template TEntity of object
|
||||
*/
|
||||
final class InsertBatch
|
||||
{
|
||||
/**
|
||||
* @param ClassMetadata<TEntity> $class
|
||||
* @param non-empty-list<TEntity> $entities
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly ClassMetadata $class,
|
||||
public array $entities,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Code in here is procedural/ugly due to it being in a hot path of the {@see UnitOfWork}
|
||||
*
|
||||
* This method will batch the given entity set by type, preserving their order. For example,
|
||||
* given an input [A1, A2, A3, B1, B2, A4, A5], it will create an [[A1, A2, A3], [B1, B2], [A4, A5]] batch.
|
||||
*
|
||||
* Entities for which the identifier needs to be generated or fetched by a sequence are put as single
|
||||
* items in a batch of their own, since it is unsafe to batch-insert them.
|
||||
*
|
||||
* @param list<TEntities> $entities
|
||||
*
|
||||
* @return list<self<TEntities>>
|
||||
*
|
||||
* @template TEntities of object
|
||||
*/
|
||||
public static function batchByEntityType(
|
||||
EntityManagerInterface $entityManager,
|
||||
array $entities,
|
||||
): array {
|
||||
$currentClass = null;
|
||||
$batches = [];
|
||||
$batchIndex = -1;
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
$entityClass = $entityManager->getClassMetadata($entity::class);
|
||||
|
||||
if (
|
||||
$currentClass?->name !== $entityClass->name
|
||||
|| ! $entityClass->idGenerator instanceof AssignedGenerator
|
||||
) {
|
||||
$currentClass = $entityClass;
|
||||
$batches[] = new InsertBatch($entityClass, [$entity]);
|
||||
$batchIndex += 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$batches[$batchIndex]->entities[] = $entity;
|
||||
}
|
||||
|
||||
return $batches;
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,7 @@ use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\ReadableCollection;
|
||||
use Doctrine\Common\Collections\Selectable;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
|
||||
use function assert;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* A lazy collection that allows a fast count when using criteria object
|
||||
@@ -26,6 +25,7 @@ use function assert;
|
||||
*/
|
||||
class LazyCriteriaCollection extends AbstractLazyCollection implements Selectable
|
||||
{
|
||||
/** @var non-negative-int|null */
|
||||
private int|null $count = null;
|
||||
|
||||
public function __construct(
|
||||
@@ -37,6 +37,7 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
|
||||
/**
|
||||
* Do an efficient count on the collection
|
||||
*/
|
||||
#[Override]
|
||||
public function count(): int
|
||||
{
|
||||
if ($this->isInitialized()) {
|
||||
@@ -54,6 +55,7 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
|
||||
/**
|
||||
* check if collection is empty without loading it
|
||||
*/
|
||||
#[Override]
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
if ($this->isInitialized()) {
|
||||
@@ -70,6 +72,7 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
|
||||
*
|
||||
* @return bool TRUE if the collection contains $element, FALSE otherwise.
|
||||
*/
|
||||
#[Override]
|
||||
public function contains(mixed $element): bool
|
||||
{
|
||||
if ($this->isInitialized()) {
|
||||
@@ -80,14 +83,15 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
|
||||
}
|
||||
|
||||
/** @return ReadableCollection<TKey, TValue>&Selectable<TKey, TValue> */
|
||||
#[Override]
|
||||
public function matching(Criteria $criteria): ReadableCollection&Selectable
|
||||
{
|
||||
$this->initialize();
|
||||
assert($this->collection instanceof Selectable);
|
||||
|
||||
return $this->collection->matching($criteria);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
protected function doInitialize(): void
|
||||
{
|
||||
$elements = $this->entityPersister->loadCriteria($this->criteria);
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\ORM\Internal\SQLResultCasing;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* ANSI compliant quote strategy, this strategy does not apply any quote.
|
||||
@@ -15,6 +16,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
{
|
||||
use SQLResultCasing;
|
||||
|
||||
#[Override]
|
||||
public function getColumnName(
|
||||
string $fieldName,
|
||||
ClassMetadata $class,
|
||||
@@ -23,6 +25,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
return $class->fieldMappings[$fieldName]->columnName;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getTableName(ClassMetadata $class, AbstractPlatform $platform): string
|
||||
{
|
||||
return $class->table['name'];
|
||||
@@ -31,16 +34,19 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform): string
|
||||
{
|
||||
return $definition['sequenceName'];
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getJoinColumnName(JoinColumnMapping $joinColumn, ClassMetadata $class, AbstractPlatform $platform): string
|
||||
{
|
||||
return $joinColumn->name;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getReferencedJoinColumnName(
|
||||
JoinColumnMapping $joinColumn,
|
||||
ClassMetadata $class,
|
||||
@@ -49,6 +55,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
return $joinColumn->referencedColumnName;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getJoinTableName(
|
||||
ManyToManyOwningSideMapping $association,
|
||||
ClassMetadata $class,
|
||||
@@ -60,11 +67,13 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
#[Override]
|
||||
public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform): array
|
||||
{
|
||||
return $class->identifier;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function getColumnAlias(
|
||||
string $columnName,
|
||||
int $counter,
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use InvalidArgumentException;
|
||||
|
||||
use function property_exists;
|
||||
|
||||
/** @internal */
|
||||
trait ArrayAccessImplementation
|
||||
{
|
||||
/** @param string $offset */
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11211',
|
||||
'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.',
|
||||
static::class,
|
||||
);
|
||||
|
||||
return isset($this->$offset);
|
||||
}
|
||||
|
||||
/** @param string $offset */
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11211',
|
||||
'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.',
|
||||
static::class,
|
||||
);
|
||||
|
||||
if (! property_exists($this, $offset)) {
|
||||
throw new InvalidArgumentException('Undefined property: ' . $offset);
|
||||
}
|
||||
|
||||
return $this->$offset;
|
||||
}
|
||||
|
||||
/** @param string $offset */
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11211',
|
||||
'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.',
|
||||
static::class,
|
||||
);
|
||||
|
||||
$this->$offset = $value;
|
||||
}
|
||||
|
||||
/** @param string $offset */
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11211',
|
||||
'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.',
|
||||
static::class,
|
||||
);
|
||||
|
||||
$this->$offset = null;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use ArrayAccess;
|
||||
use Exception;
|
||||
use OutOfRangeException;
|
||||
|
||||
@@ -14,8 +13,7 @@ use function in_array;
|
||||
use function property_exists;
|
||||
use function sprintf;
|
||||
|
||||
/** @template-implements ArrayAccess<string, mixed> */
|
||||
abstract class AssociationMapping implements ArrayAccess
|
||||
abstract class AssociationMapping
|
||||
{
|
||||
/**
|
||||
* The names of persistence operations to cascade on the association.
|
||||
|
||||
@@ -113,6 +113,10 @@ class AssociationBuilder
|
||||
string|null $onDelete = null,
|
||||
string|null $columnDef = null,
|
||||
): static {
|
||||
if ($this->mapping['id'] ?? false) {
|
||||
$nullable = null;
|
||||
}
|
||||
|
||||
$this->joinColumns[] = [
|
||||
'name' => $columnName,
|
||||
'referencedColumnName' => $referencedColumnName,
|
||||
@@ -133,6 +137,9 @@ class AssociationBuilder
|
||||
public function makePrimaryKey(): static
|
||||
{
|
||||
$this->mapping['id'] = true;
|
||||
foreach ($this->joinColumns ?? [] as $i => $joinColumn) {
|
||||
$this->joinColumns[$i]['nullable'] = null;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use function get_class_methods;
|
||||
class EntityListenerBuilder
|
||||
{
|
||||
/** Hash-map to handle event names. */
|
||||
private const EVENTS = [
|
||||
private const array EVENTS = [
|
||||
Events::preRemove => true,
|
||||
Events::postRemove => true,
|
||||
Events::prePersist => true,
|
||||
|
||||
@@ -64,6 +64,18 @@ class FieldBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets indexed.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function index(bool $flag = true): static
|
||||
{
|
||||
$this->mapping['index'] = $flag;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets column name.
|
||||
*
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Builder;
|
||||
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* ManyToMany Association Builder
|
||||
*
|
||||
@@ -24,6 +26,31 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Join Columns.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
#[Override]
|
||||
public function addJoinColumn(
|
||||
string $columnName,
|
||||
string $referencedColumnName,
|
||||
bool $nullable = true,
|
||||
bool $unique = false,
|
||||
string|null $onDelete = null,
|
||||
string|null $columnDef = null,
|
||||
): static {
|
||||
$this->joinColumns[] = [
|
||||
'name' => $columnName,
|
||||
'referencedColumnName' => $referencedColumnName,
|
||||
'unique' => $unique,
|
||||
'onDelete' => $onDelete,
|
||||
'columnDefinition' => $columnDef,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds Inverse Join Columns.
|
||||
*
|
||||
@@ -40,7 +67,6 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
|
||||
$this->inverseJoinColumns[] = [
|
||||
'name' => $columnName,
|
||||
'referencedColumnName' => $referencedColumnName,
|
||||
'nullable' => $nullable,
|
||||
'unique' => $unique,
|
||||
'onDelete' => $onDelete,
|
||||
'columnDefinition' => $columnDef,
|
||||
@@ -49,6 +75,7 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function build(): ClassMetadataBuilder
|
||||
{
|
||||
$mapping = $this->mapping;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user