mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 06:52:09 +01:00
Compare commits
1342 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a541b8b3a | ||
|
|
9fb9cc46e4 | ||
|
|
c322c71cd4 | ||
|
|
3c733a2fee | ||
|
|
5984ad586a | ||
|
|
ee2c3a506b | ||
|
|
781ed30926 | ||
|
|
04694a9f7b | ||
|
|
257c5094c4 | ||
|
|
66e0e92816 | ||
|
|
5b2060e25f | ||
|
|
64444dcfd5 | ||
|
|
eb2cd5375c | ||
|
|
de7140e105 | ||
|
|
39e35fc06c | ||
|
|
7f061c3870 | ||
|
|
74495711fb | ||
|
|
97a7cb8d2f | ||
|
|
85d66de9df | ||
|
|
1b98be31ce | ||
|
|
61f2752a80 | ||
|
|
f3371e1773 | ||
|
|
6476894dc4 | ||
|
|
e0052390e1 | ||
|
|
8c6419e0e0 | ||
|
|
6f5ce1aca2 | ||
|
|
98e7a53b42 | ||
|
|
3aaaf37dfb | ||
|
|
154a4652ee | ||
|
|
ae7489ff19 | ||
|
|
0f32569a7a | ||
|
|
d99f74c704 | ||
|
|
62ca8424d8 | ||
|
|
3f2209a571 | ||
|
|
1ee01f4473 | ||
|
|
8a9ed138a8 | ||
|
|
e714b1a2fc | ||
|
|
ec0bf05853 | ||
|
|
dc58aa3ea1 | ||
|
|
23b74e4f8b | ||
|
|
d2b699e6f5 | ||
|
|
0338d69324 | ||
|
|
2c01dac173 | ||
|
|
137ecb491a | ||
|
|
f38ee09082 | ||
|
|
6ab858a5c5 | ||
|
|
3dca27ce0d | ||
|
|
e19704e1f8 | ||
|
|
41ea59ac66 | ||
|
|
e605e6d569 | ||
|
|
9437675d3b | ||
|
|
63409d638c | ||
|
|
9b9160b206 | ||
|
|
6deec3655b | ||
|
|
7f40422d21 | ||
|
|
e67fa5388b | ||
|
|
80053336c9 | ||
|
|
dddcc507ef | ||
|
|
b41d9da88d | ||
|
|
c04bfb78b7 | ||
|
|
8a5dfc86d4 | ||
|
|
79e103c07e | ||
|
|
5afadf163a | ||
|
|
edfaa37228 | ||
|
|
ea056e98ba | ||
|
|
bab5771e98 | ||
|
|
ee919d6231 | ||
|
|
04c390693a | ||
|
|
49293c4d48 | ||
|
|
8d9e2e7d4e | ||
|
|
ef607f26c2 | ||
|
|
ed543a205c | ||
|
|
de1c28bb16 | ||
|
|
60ff966d54 | ||
|
|
33684253c3 | ||
|
|
b4ca0cd5fb | ||
|
|
a49c1beb93 | ||
|
|
76852cfef3 | ||
|
|
3bd89caf36 | ||
|
|
eb2e7d959c | ||
|
|
a4b20356f4 | ||
|
|
2550b2d1de | ||
|
|
e94e1ab126 | ||
|
|
6307b4fa7d | ||
|
|
19e1a64a91 | ||
|
|
082e776e91 | ||
|
|
92e2f6db83 | ||
|
|
aa624f64c1 | ||
|
|
e1675eb371 | ||
|
|
cc2b6385a1 | ||
|
|
a64bed9bbb | ||
|
|
3272e1c0af | ||
|
|
69da22d517 | ||
|
|
06109f360f | ||
|
|
06a9ef1127 | ||
|
|
5d21bb158b | ||
|
|
bbde41f712 | ||
|
|
8c0994f35f | ||
|
|
3d390bc053 | ||
|
|
16f1be7f10 | ||
|
|
c74df3fab3 | ||
|
|
f2c902ee03 | ||
|
|
4e5e3c5e50 | ||
|
|
da697f218f | ||
|
|
4f47a80deb | ||
|
|
1334162a56 | ||
|
|
ab89517093 | ||
|
|
48a51d8470 | ||
|
|
ab11244f08 | ||
|
|
68ec3ebaa3 | ||
|
|
4f4ed2f242 | ||
|
|
a1c2be140d | ||
|
|
4664373bd0 | ||
|
|
5ab6b74f14 | ||
|
|
79cc70a62f | ||
|
|
4e6b5a1b0b | ||
|
|
21b144fff9 | ||
|
|
658940de38 | ||
|
|
ad487370f5 | ||
|
|
259f83b549 | ||
|
|
4a24860dcf | ||
|
|
116cdf8661 | ||
|
|
71550106d4 | ||
|
|
36011f0d0f | ||
|
|
c97d775370 | ||
|
|
97b29bb063 | ||
|
|
e9f0345a97 | ||
|
|
b7fff508a4 | ||
|
|
c6fa14ed52 | ||
|
|
05c8c5f114 | ||
|
|
1dbdb0e895 | ||
|
|
0feb09d0d6 | ||
|
|
fe5f8bbaa1 | ||
|
|
ecf3cec376 | ||
|
|
0a714db4d9 | ||
|
|
471fda8d0b | ||
|
|
dfe32c2f74 | ||
|
|
c51ba3ce6b | ||
|
|
fe025e8d23 | ||
|
|
0a43e4af8f | ||
|
|
7111cc09f3 | ||
|
|
777504b9c4 | ||
|
|
9d9985076a | ||
|
|
35d301b052 | ||
|
|
083b241c81 | ||
|
|
ae2957cf7e | ||
|
|
e172b3bf9c | ||
|
|
c9c6e8da2e | ||
|
|
528b8837e1 | ||
|
|
b9989555fd | ||
|
|
80a79f6d2d | ||
|
|
1f1891d3e2 | ||
|
|
c9fc4d90e5 | ||
|
|
17d28b5c4c | ||
|
|
a2d510c6f4 | ||
|
|
0e3cff0c6a | ||
|
|
5c50ed925a | ||
|
|
5a1e560f87 | ||
|
|
78e8887759 | ||
|
|
9a3f5579f1 | ||
|
|
5eb298b99b | ||
|
|
5eb0255f47 | ||
|
|
28575f58af | ||
|
|
457d2d2841 | ||
|
|
12c721f528 | ||
|
|
9a9c3e8aba | ||
|
|
2a4ebca90e | ||
|
|
5d01c66c84 | ||
|
|
a2516b67dc | ||
|
|
46a020108d | ||
|
|
3d4e9b3ecf | ||
|
|
d1ee40e7d5 | ||
|
|
65d2720764 | ||
|
|
3e18a58de6 | ||
|
|
a9f9202c00 | ||
|
|
d8cb71fe4a | ||
|
|
d659591b6c | ||
|
|
e2430ac9a7 | ||
|
|
b286d6cd2c | ||
|
|
0b373f6c27 | ||
|
|
443cf92242 | ||
|
|
36b9064dbe | ||
|
|
eb3b984132 | ||
|
|
cc29ae0d36 | ||
|
|
bd4a053d29 | ||
|
|
52fbfb3785 | ||
|
|
c259371e5f | ||
|
|
dcdd58b642 | ||
|
|
7b9c53854f | ||
|
|
cdc5fe11dd | ||
|
|
69ece00564 | ||
|
|
04395f98f9 | ||
|
|
4baa7bd252 | ||
|
|
c55f10e501 | ||
|
|
f3fb79658e | ||
|
|
10a32cb824 | ||
|
|
c679d1b007 | ||
|
|
1e15b22dcb | ||
|
|
0c10010f9f | ||
|
|
d88371331d | ||
|
|
b260ec8a00 | ||
|
|
44057b4683 | ||
|
|
013df03795 | ||
|
|
2d2a34407c | ||
|
|
be8da83aca | ||
|
|
f5ab687226 | ||
|
|
742eead849 | ||
|
|
1072ea6db4 | ||
|
|
baf2c60cc4 | ||
|
|
8e620cad40 | ||
|
|
f98e871913 | ||
|
|
4b0c11978e | ||
|
|
daf0f82884 | ||
|
|
067ad51b3f | ||
|
|
0ef5610a6c | ||
|
|
e29d0e977d | ||
|
|
00c77213fb | ||
|
|
3303cd3b5d | ||
|
|
afcf91e839 | ||
|
|
c61a9b3b6d | ||
|
|
bd0509a064 | ||
|
|
c68b8f90b3 | ||
|
|
aa4f9ce9e9 | ||
|
|
d540f73778 | ||
|
|
d96fc23327 | ||
|
|
201d751a26 | ||
|
|
6308b2fd86 | ||
|
|
8f99e84438 | ||
|
|
e36b7755e9 | ||
|
|
7b4d869b31 | ||
|
|
708bd84fe2 | ||
|
|
3aed6912a3 | ||
|
|
4fb044d5f6 | ||
|
|
8873109b4f | ||
|
|
36bef3f959 | ||
|
|
980ccc58dc | ||
|
|
62ca4624a9 | ||
|
|
1aed318b7b | ||
|
|
8ce7b310c5 | ||
|
|
2a953c5e2b | ||
|
|
5077ae41e5 | ||
|
|
8e1a27b8cc | ||
|
|
e7db1b005f | ||
|
|
72ce662e45 | ||
|
|
673cf0d4d8 | ||
|
|
1cae0534a0 | ||
|
|
6fb3083f63 | ||
|
|
68c17ca1bd | ||
|
|
82cf29407c | ||
|
|
abc6a40ccb | ||
|
|
158605bf24 | ||
|
|
2c2ef65817 | ||
|
|
f8fdeaf41e | ||
|
|
1c33a86983 | ||
|
|
310fe1cccb | ||
|
|
a67f677747 | ||
|
|
ae74be5e9d | ||
|
|
c9557c588b | ||
|
|
73e68f3c7d | ||
|
|
19912de927 | ||
|
|
737cca5b78 | ||
|
|
4163efd2f2 | ||
|
|
d7ac6123ad | ||
|
|
aff82af7de | ||
|
|
9e999ea1ff | ||
|
|
6755bb0c7b | ||
|
|
73777d0bd4 | ||
|
|
bd260d1be8 | ||
|
|
aa141bf001 | ||
|
|
cd1a52c7e4 | ||
|
|
cf39e00553 | ||
|
|
27b47841be | ||
|
|
c2a49327a7 | ||
|
|
9bd7242376 | ||
|
|
fff085b63f | ||
|
|
5ad5b11ae1 | ||
|
|
c12fd2cb94 | ||
|
|
44d5d4a779 | ||
|
|
5a599233c9 | ||
|
|
596da353c2 | ||
|
|
0d2cb6acd1 | ||
|
|
ec6d1b9f72 | ||
|
|
d809fed52a | ||
|
|
327418a4b7 | ||
|
|
0e4786dfa8 | ||
|
|
c429262f02 | ||
|
|
f4fdcbcdcb | ||
|
|
b0806469d5 | ||
|
|
68c87740aa | ||
|
|
55dc02c39f | ||
|
|
9f2b367081 | ||
|
|
a9873c86bb | ||
|
|
8ebd98ee92 | ||
|
|
e89b58a13f | ||
|
|
b1f8253105 | ||
|
|
e3cabade99 | ||
|
|
9402f9e0f7 | ||
|
|
4feaa470af | ||
|
|
4a9101f383 | ||
|
|
f91da5b950 | ||
|
|
66f654d4e2 | ||
|
|
7b9c0d91f6 | ||
|
|
53b51ae40e | ||
|
|
95b0f5c328 | ||
|
|
5a220078e9 | ||
|
|
2b94ec18b9 | ||
|
|
a15543a2ce | ||
|
|
238fb74028 | ||
|
|
6ff2b130d3 | ||
|
|
8c9bfca255 | ||
|
|
c2a2386df9 | ||
|
|
2f98e11562 | ||
|
|
073809cf5c | ||
|
|
e82690d256 | ||
|
|
23c31aec51 | ||
|
|
622ba2dcc7 | ||
|
|
0c1cf853fc | ||
|
|
79d1f07fa2 | ||
|
|
eba01f8d0e | ||
|
|
bd292481bd | ||
|
|
fcc53b260f | ||
|
|
7d61a1e73f | ||
|
|
b3cffe2d12 | ||
|
|
46c94e3729 | ||
|
|
052c7d7698 | ||
|
|
c2713adebc | ||
|
|
4e01567816 | ||
|
|
51a984be3d | ||
|
|
f7f3104451 | ||
|
|
a5c80a4c75 | ||
|
|
417444d4b5 | ||
|
|
6fd26a3933 | ||
|
|
8ef9253999 | ||
|
|
360b80afab | ||
|
|
2a662149f4 | ||
|
|
0ed0be089c | ||
|
|
8fb1043e96 | ||
|
|
fd041fbe80 | ||
|
|
6007154484 | ||
|
|
22ce0aff37 | ||
|
|
5d73458f0b | ||
|
|
6c70d11f4e | ||
|
|
eadf96c879 | ||
|
|
0d770c89d6 | ||
|
|
0a635c1ece | ||
|
|
37051d57ce | ||
|
|
69a4199434 | ||
|
|
4bda5147f3 | ||
|
|
cbda7e2322 | ||
|
|
4563f2f9a7 | ||
|
|
38c6569645 | ||
|
|
7c0eebe90a | ||
|
|
8784f2bce9 | ||
|
|
fbcac42ebd | ||
|
|
619302dc9a | ||
|
|
50d7a0f95e | ||
|
|
d7f13a82ef | ||
|
|
9e1038075e | ||
|
|
dd3604f523 | ||
|
|
65e9f607e5 | ||
|
|
a42134ccee | ||
|
|
71e038c81d | ||
|
|
91201c094a | ||
|
|
2ff998da0e | ||
|
|
82e2c981da | ||
|
|
8422a41423 | ||
|
|
58ad1d9678 | ||
|
|
346c49832c | ||
|
|
f140651ff0 | ||
|
|
bb5b2a3300 | ||
|
|
5013d5dbef | ||
|
|
ba11851ac4 | ||
|
|
4fbce94999 | ||
|
|
486e406236 | ||
|
|
7d1b24f3b1 | ||
|
|
43ce0bef78 | ||
|
|
da51234d5a | ||
|
|
d9aa6ef6dc | ||
|
|
ff3ccff36a | ||
|
|
4b03ec7789 | ||
|
|
14866461c5 | ||
|
|
f41dc4a503 | ||
|
|
81c0d599c9 | ||
|
|
9e2bfa8169 | ||
|
|
44fa8bbde8 | ||
|
|
3ca9529c32 | ||
|
|
439b4dacf4 | ||
|
|
05f54860f7 | ||
|
|
021a9cce3d | ||
|
|
0f11a97c8e | ||
|
|
c9253ef64b | ||
|
|
af54a1696c | ||
|
|
4d821cb139 | ||
|
|
85fc95060f | ||
|
|
039b03255a | ||
|
|
e7efdede15 | ||
|
|
74155c8672 | ||
|
|
a4a15ad243 | ||
|
|
9c0e62ad44 | ||
|
|
94702d14b9 | ||
|
|
5aad44cff6 | ||
|
|
182469b346 | ||
|
|
0893d8511e | ||
|
|
e47398ecc5 | ||
|
|
9e884ccf1f | ||
|
|
fac0899ef7 | ||
|
|
d5c400e8d1 | ||
|
|
6648d68ddf | ||
|
|
982d6060a3 | ||
|
|
013f850c76 | ||
|
|
ef4508e52f | ||
|
|
6dae89ce0d | ||
|
|
f53350934f | ||
|
|
efaba02ef5 | ||
|
|
4ff909044e | ||
|
|
32682aa14d | ||
|
|
e9f3ca2a45 | ||
|
|
737aee7d98 | ||
|
|
bd20df1043 | ||
|
|
69958152e6 | ||
|
|
cf8f5f9f93 | ||
|
|
60c245413d | ||
|
|
7c9b74221f | ||
|
|
2ec2030ab2 | ||
|
|
c7e5605d11 | ||
|
|
c19afa1529 | ||
|
|
516b593193 | ||
|
|
e2b971d7c5 | ||
|
|
19d9244a88 | ||
|
|
10a5a3ff73 | ||
|
|
f5fb400d0f | ||
|
|
a321331c89 | ||
|
|
522863116a | ||
|
|
5bfb744967 | ||
|
|
8ed6c2234a | ||
|
|
ff612b9678 | ||
|
|
ee0d7197dd | ||
|
|
39d2136f46 | ||
|
|
c223b8f635 | ||
|
|
bea454eefc | ||
|
|
14f2572e4e | ||
|
|
c2c500077b | ||
|
|
6281c2b79f | ||
|
|
bac1c17eab | ||
|
|
b6137c8911 | ||
|
|
da7854f586 | ||
|
|
5f4ecfd1d8 | ||
|
|
51be1b1d52 | ||
|
|
5f39343bfd | ||
|
|
7ef1f0a379 | ||
|
|
488a5dd3bf | ||
|
|
30795559dc | ||
|
|
f71725575c | ||
|
|
4a3c7f05bf | ||
|
|
896c65504d | ||
|
|
16a8f10fd2 | ||
|
|
498de4c564 | ||
|
|
d80a831157 | ||
|
|
52660297ab | ||
|
|
b44774285b | ||
|
|
58287bb731 | ||
|
|
bc37f75b41 | ||
|
|
8a25b264f7 | ||
|
|
0e48b19cd3 | ||
|
|
d2978303f0 | ||
|
|
109042e5af | ||
|
|
08328adc6c | ||
|
|
191a5366b1 | ||
|
|
65806884b0 | ||
|
|
ad80e8281a | ||
|
|
44dddb2eee | ||
|
|
0c0c61c51b | ||
|
|
cc28fed9f5 | ||
|
|
2245149588 | ||
|
|
b13564c6c0 | ||
|
|
91709c1275 | ||
|
|
434b7cee2a | ||
|
|
7f0a181e39 | ||
|
|
d18126aac5 | ||
|
|
b7fd8241cf | ||
|
|
2432939e4f | ||
|
|
93ce84fa6e | ||
|
|
1bf4603422 | ||
|
|
e6961bd968 | ||
|
|
25d5bc5b46 | ||
|
|
5724e6279e | ||
|
|
cfc0655a1c | ||
|
|
6cde337777 | ||
|
|
c6b2d89748 | ||
|
|
e1dc94d1c2 | ||
|
|
74ef28295a | ||
|
|
831a1eb7d2 | ||
|
|
3a82b153f3 | ||
|
|
6f93cebe6e | ||
|
|
8c582a49d3 | ||
|
|
5f1fe1587c | ||
|
|
205b2f5f20 | ||
|
|
3f550c19e3 | ||
|
|
56cd688c4a | ||
|
|
96546caceb | ||
|
|
57247ed6ca | ||
|
|
12817076c3 | ||
|
|
129553da90 | ||
|
|
4c2f104d42 | ||
|
|
ef64cf7c33 | ||
|
|
0983d3a4af | ||
|
|
1fe1a6a048 | ||
|
|
efe62e3f0b | ||
|
|
7d01f19667 | ||
|
|
722cea6536 | ||
|
|
ce7d93f14d | ||
|
|
a139a1b63c | ||
|
|
1153b9468c | ||
|
|
d0e9177121 | ||
|
|
428032ca7c | ||
|
|
f666aa641e | ||
|
|
ca3319c2f6 | ||
|
|
c06f6b9376 | ||
|
|
ed53defaa1 | ||
|
|
41cb5fbbbf | ||
|
|
83851a9716 | ||
|
|
066ec1ac81 | ||
|
|
68744489f0 | ||
|
|
9d4f54b9a4 | ||
|
|
37946d3a21 | ||
|
|
baf96cdad4 | ||
|
|
ce09c96427 | ||
|
|
ae659fe650 | ||
|
|
0a177d5074 | ||
|
|
dbfe47b07b | ||
|
|
bf3e082c00 | ||
|
|
22b1f52c1c | ||
|
|
a90ee5c495 | ||
|
|
11270425e5 | ||
|
|
f1246d57c2 | ||
|
|
a14ef7c279 | ||
|
|
54c29140fa | ||
|
|
eb49f66926 | ||
|
|
73e30df52b | ||
|
|
daa99f197b | ||
|
|
2b04cc2e3f | ||
|
|
3d9af3187f | ||
|
|
e83d8a80ba | ||
|
|
029ca611f0 | ||
|
|
9e7715f678 | ||
|
|
0e26e3ed50 | ||
|
|
63315c8e4a | ||
|
|
8ca99fdfdc | ||
|
|
8b6a58fa0e | ||
|
|
2d8e466636 | ||
|
|
97634ae6a1 | ||
|
|
b725908c83 | ||
|
|
f79d166a4e | ||
|
|
9c22814cfa | ||
|
|
e0e55dc9c5 | ||
|
|
010b1e0886 | ||
|
|
93eb8a1bcb | ||
|
|
1464827220 | ||
|
|
cbb6c897de | ||
|
|
753bc16c0b | ||
|
|
be307edba8 | ||
|
|
4672d284ff | ||
|
|
9c56071392 | ||
|
|
0a1988b349 | ||
|
|
083f642cfa | ||
|
|
4175edf311 | ||
|
|
716da7e538 | ||
|
|
67ac5a82da | ||
|
|
e384978e0b | ||
|
|
55c4845d57 | ||
|
|
a38f473a92 | ||
|
|
bcdc5bdaf4 | ||
|
|
69f51cc794 | ||
|
|
7178b9d6b7 | ||
|
|
8a14eee67a | ||
|
|
f9331ee2b9 | ||
|
|
c5315f86fb | ||
|
|
5820bb8f49 | ||
|
|
80278c545e | ||
|
|
cb05f1aadf | ||
|
|
ab616f1a1d | ||
|
|
90962f060a | ||
|
|
758f0d7605 | ||
|
|
eb8510ff5c | ||
|
|
d5fdd676f4 | ||
|
|
b0d07ffaba | ||
|
|
196d3a6996 | ||
|
|
a3e3a3bbf3 | ||
|
|
7d1444e5b6 | ||
|
|
25d5936337 | ||
|
|
68f9bf5dfa | ||
|
|
0a49274f9b | ||
|
|
716fc97b70 | ||
|
|
4617a5e310 | ||
|
|
e77c5a3a5e | ||
|
|
c3cc0fdd8c | ||
|
|
507c73c073 | ||
|
|
ba0ea8953b | ||
|
|
53763d432b | ||
|
|
154920a0b3 | ||
|
|
b8d0a85017 | ||
|
|
cb497826be | ||
|
|
ba0d3842a9 | ||
|
|
bf49055a1f | ||
|
|
29e1935c65 | ||
|
|
694413a888 | ||
|
|
33e02b2796 | ||
|
|
26f7588479 | ||
|
|
20a6efdff6 | ||
|
|
95da667862 | ||
|
|
c02ddd692f | ||
|
|
151a3fba9d | ||
|
|
b187bc8588 | ||
|
|
1e056842fe | ||
|
|
ebb0c67ecc | ||
|
|
3f7a3333ad | ||
|
|
2a8802af12 | ||
|
|
9cc11d2541 | ||
|
|
ee5b2ce5b0 | ||
|
|
d54c9678d0 | ||
|
|
859e6af972 | ||
|
|
8c3c9f115d | ||
|
|
3907872046 | ||
|
|
54cd70002c | ||
|
|
2df4d75565 | ||
|
|
dc21ab63ac | ||
|
|
2a250b5814 | ||
|
|
44fa5d340a | ||
|
|
708146bbbc | ||
|
|
a5bf9bb96a | ||
|
|
3eace16e85 | ||
|
|
e4c27092cd | ||
|
|
adadf1fb90 | ||
|
|
380b5b62ef | ||
|
|
a0e7a59572 | ||
|
|
fb6c0c1d8b | ||
|
|
fcf1116e33 | ||
|
|
78dc63df27 | ||
|
|
bc5efd4bfe | ||
|
|
b6b4cbcb93 | ||
|
|
b1f553eba3 | ||
|
|
0c4aac5a35 | ||
|
|
e0081b59be | ||
|
|
4bd574daee | ||
|
|
d5ba106803 | ||
|
|
f9a4adc8ab | ||
|
|
6672aaf165 | ||
|
|
aa3b331cae | ||
|
|
3918dcfb42 | ||
|
|
6290747bf9 | ||
|
|
b6f4220493 | ||
|
|
bfb033fe3c | ||
|
|
bf86155dc2 | ||
|
|
9acc70d5b8 | ||
|
|
b7860c782b | ||
|
|
9a24ce5fad | ||
|
|
9fcb8f1305 | ||
|
|
5a40b99e11 | ||
|
|
94144e1227 | ||
|
|
599dd58fe1 | ||
|
|
aff543a4ff | ||
|
|
1854ce2d32 | ||
|
|
b00f0c258e | ||
|
|
13a79b068c | ||
|
|
27c9e9cab3 | ||
|
|
1051817d92 | ||
|
|
00ed2ca991 | ||
|
|
54b7ad2073 | ||
|
|
517d038e5b | ||
|
|
3db79ebbf3 | ||
|
|
a2faeb9a26 | ||
|
|
3764ebf7a3 | ||
|
|
a7d5adb3ce | ||
|
|
6f507c322a | ||
|
|
54013671a7 | ||
|
|
f5dea25b6c | ||
|
|
7527b788de | ||
|
|
e52bc846f0 | ||
|
|
f259754b7c | ||
|
|
3bc2cb6b15 | ||
|
|
5b8b5f28f5 | ||
|
|
2e155e98a7 | ||
|
|
c7a91a459c | ||
|
|
1df03f21e6 | ||
|
|
09f0966ad6 | ||
|
|
da6c6f7045 | ||
|
|
fd8d981f30 | ||
|
|
db4d00a58f | ||
|
|
1a5942a4d9 | ||
|
|
282b8fbfe8 | ||
|
|
537a27d277 | ||
|
|
cf7757e090 | ||
|
|
69cc78c259 | ||
|
|
2893394673 | ||
|
|
8aa6a5f401 | ||
|
|
588d29d789 | ||
|
|
0a3fbac8af | ||
|
|
1556a1ff7a | ||
|
|
64e4a2129c | ||
|
|
7361d3e57d | ||
|
|
28d03e41f7 | ||
|
|
f8ced51687 | ||
|
|
2c06ffa4a7 | ||
|
|
9a281f54de | ||
|
|
b73d44b46b | ||
|
|
b971cbeebb | ||
|
|
fcba06f64c | ||
|
|
7974a92bf9 | ||
|
|
124593383b | ||
|
|
56df970d8b | ||
|
|
21466a0524 | ||
|
|
010cd948c9 | ||
|
|
30626ac6bb | ||
|
|
1f62233bf6 | ||
|
|
ffbe56779d | ||
|
|
bdc039fe31 | ||
|
|
73288bc472 | ||
|
|
8ab0af3d30 | ||
|
|
82f4a177b2 | ||
|
|
1fef3196d9 | ||
|
|
ad519a5c6f | ||
|
|
4444065531 | ||
|
|
e280b2df26 | ||
|
|
3c34265666 | ||
|
|
8693fa790c | ||
|
|
e997c6688c | ||
|
|
03148b1300 | ||
|
|
f47d68c826 | ||
|
|
06eb00d687 | ||
|
|
7827453b94 | ||
|
|
6f3140a09e | ||
|
|
2d31d71961 | ||
|
|
2db1f76dee | ||
|
|
6e61571edc | ||
|
|
22e7c02cf7 | ||
|
|
4a5f48f7ff | ||
|
|
5534db1810 | ||
|
|
18897fa7d5 | ||
|
|
689da1f251 | ||
|
|
5c250063b8 | ||
|
|
99fe3b5c5b | ||
|
|
af5c250cc8 | ||
|
|
1fe0910d6b | ||
|
|
2cf0c59f7a | ||
|
|
7e51a09347 | ||
|
|
906e91cbb4 | ||
|
|
2aaec3a79a | ||
|
|
4799c418c9 | ||
|
|
a1d7de6b66 | ||
|
|
83d46d7cf9 | ||
|
|
f3b6c4b356 | ||
|
|
343afda275 | ||
|
|
27009986d7 | ||
|
|
e71868fe8b | ||
|
|
795e7735d8 | ||
|
|
46ef989f38 | ||
|
|
8a4d35d5e7 | ||
|
|
faec95fed2 | ||
|
|
c69044bc9b | ||
|
|
9a1085d72f | ||
|
|
501226b90b | ||
|
|
2c39b3f118 | ||
|
|
436f0467ec | ||
|
|
394f6fe1b4 | ||
|
|
7d9a2c0a71 | ||
|
|
2dc19e6919 | ||
|
|
b68cab1b3d | ||
|
|
476b68cd1f | ||
|
|
3ffd3f6509 | ||
|
|
1733bf8678 | ||
|
|
84a87a6ac8 | ||
|
|
6fa95b93df | ||
|
|
2004761475 | ||
|
|
3ad9c43a96 | ||
|
|
1bd3066b9f | ||
|
|
663763ab1a | ||
|
|
2a8f22c521 | ||
|
|
efd429dd24 | ||
|
|
716139c168 | ||
|
|
492635a8e8 | ||
|
|
0dad2daf2c | ||
|
|
e0b72408a1 | ||
|
|
575d0c03ee | ||
|
|
a2a4f73b30 | ||
|
|
f1d6ba8919 | ||
|
|
0872d1429d | ||
|
|
96f5f84e8b | ||
|
|
0945f60484 | ||
|
|
f38922944e | ||
|
|
63e9ad9e9a | ||
|
|
46ff264502 | ||
|
|
8b1ce48e79 | ||
|
|
07674b1887 | ||
|
|
ec43884612 | ||
|
|
ee62934911 | ||
|
|
8a6dbb4ae2 | ||
|
|
2a8a886bbe | ||
|
|
2b03858717 | ||
|
|
497faffe0b | ||
|
|
8a762f04f1 | ||
|
|
bbc56aaec6 | ||
|
|
647712649b | ||
|
|
61f2c4d53b | ||
|
|
ca8ee91467 | ||
|
|
2987e9956f | ||
|
|
917e0cff39 | ||
|
|
6ce0cf4a3d | ||
|
|
d4915a8b3d | ||
|
|
749947efe7 | ||
|
|
535d869835 | ||
|
|
ea23628010 | ||
|
|
10fa1e07b2 | ||
|
|
c32efc2588 | ||
|
|
6032a2ccf7 | ||
|
|
1f9d1bf4cb | ||
|
|
dff40cf351 | ||
|
|
a55c72b47d | ||
|
|
f03db50be1 | ||
|
|
2a77776c91 | ||
|
|
c51c84fc47 | ||
|
|
00beecce74 | ||
|
|
9f60fdc288 | ||
|
|
3b88e4844a | ||
|
|
63561fc382 | ||
|
|
caa8041963 | ||
|
|
1c8b5181b5 | ||
|
|
e5eaf9b855 | ||
|
|
380f8a42f3 | ||
|
|
05b5a64cb9 | ||
|
|
05678dcd97 | ||
|
|
a9c80c2293 | ||
|
|
e18b80c1bf | ||
|
|
3ddb2a845c | ||
|
|
9baf213673 | ||
|
|
f874bc85f1 | ||
|
|
d075f5d5f8 | ||
|
|
fac8d84fdb | ||
|
|
09680b18ee | ||
|
|
caf8d876da | ||
|
|
629c600b10 | ||
|
|
7f46fad0f0 | ||
|
|
559e1d139a | ||
|
|
bd9cd989a0 | ||
|
|
f7e49a53be | ||
|
|
ade5559ed5 | ||
|
|
c019f8649b | ||
|
|
68571184ca | ||
|
|
f171d49dc0 | ||
|
|
ae88844353 | ||
|
|
8d1d32ce81 | ||
|
|
01aa9a5870 | ||
|
|
bf7ffa94cf | ||
|
|
672ff01f44 | ||
|
|
fd64e137c8 | ||
|
|
49cc83d273 | ||
|
|
ada109bc90 | ||
|
|
303baeea33 | ||
|
|
eeae5734a5 | ||
|
|
b6860328c0 | ||
|
|
3e04516740 | ||
|
|
ec9e79a35b | ||
|
|
2d3e89e2cb | ||
|
|
727a9914f2 | ||
|
|
5aebfefc45 | ||
|
|
118eb87032 | ||
|
|
7df7503af6 | ||
|
|
c49bba7a5e | ||
|
|
2acb298e74 | ||
|
|
eaac5cd3dc | ||
|
|
14d615201e | ||
|
|
545070f879 | ||
|
|
9d3ae4a55a | ||
|
|
c213974234 | ||
|
|
e22592f06b | ||
|
|
e4a7403ead | ||
|
|
175cdefd67 | ||
|
|
e8376b3995 | ||
|
|
b87f86e6f0 | ||
|
|
df7a5bc712 | ||
|
|
fc314a2abf | ||
|
|
ebfab93d15 | ||
|
|
13d8695780 | ||
|
|
cc72796fff | ||
|
|
35a29731bb | ||
|
|
7568328a6d | ||
|
|
b904f44c6c | ||
|
|
46ab755728 | ||
|
|
476ffd5cd8 | ||
|
|
59fb8ca571 | ||
|
|
c44e19a5e7 | ||
|
|
b69e8e0267 | ||
|
|
4444a29c14 | ||
|
|
9c2c1178e2 | ||
|
|
f98b33f764 | ||
|
|
759ae5678f | ||
|
|
6b61e52baa | ||
|
|
21c3f4d826 | ||
|
|
7a7464e6d3 | ||
|
|
0f77181a2c | ||
|
|
f86fa175df | ||
|
|
f5e7ddb21c | ||
|
|
7e2eb61deb | ||
|
|
dfcb20ea1e | ||
|
|
ce03a61b7a | ||
|
|
0f25ae4b83 | ||
|
|
4fe224a320 | ||
|
|
703648580a | ||
|
|
09caeb2753 | ||
|
|
7f9827df4f | ||
|
|
941292fe85 | ||
|
|
de8b444938 | ||
|
|
e8c1e6c1d3 | ||
|
|
4ad077b3d7 | ||
|
|
9415275195 | ||
|
|
5c34678580 | ||
|
|
642a20bcff | ||
|
|
4d8cf2698e | ||
|
|
5233a139bb | ||
|
|
fbcf91d074 | ||
|
|
3d1f172788 | ||
|
|
6ea4411789 | ||
|
|
4357161c3d | ||
|
|
3b5bd316e6 | ||
|
|
2d92c09101 | ||
|
|
4c1e520bd3 | ||
|
|
7a08253f18 | ||
|
|
e6382d393e | ||
|
|
3cd65b12a8 | ||
|
|
d4c53a8885 | ||
|
|
c8b0931f9c | ||
|
|
c226b951b3 | ||
|
|
91b662edb6 | ||
|
|
c313440962 | ||
|
|
a86d5a799d | ||
|
|
9b1f397ab2 | ||
|
|
d83b1e338c | ||
|
|
07937b5b9a | ||
|
|
a3db423eab | ||
|
|
2b2f4e8acc | ||
|
|
84e78b8200 | ||
|
|
601948baaa | ||
|
|
19168ca8d6 | ||
|
|
5e828e20cf | ||
|
|
3a10714d6f | ||
|
|
7e379f6872 | ||
|
|
8b1c353650 | ||
|
|
75bff1d983 | ||
|
|
8b35dae5a9 | ||
|
|
9062af45ca | ||
|
|
57f256912a | ||
|
|
b31afda33b | ||
|
|
ccb9ef7246 | ||
|
|
bdb3fc72da | ||
|
|
8aa05b89a0 | ||
|
|
d8a2e329b6 | ||
|
|
ad58c6a6e2 | ||
|
|
8f360f08c5 | ||
|
|
2e2bca8cf8 | ||
|
|
32eae38f07 | ||
|
|
3a2bfce92c | ||
|
|
57e18d0b1b | ||
|
|
b3f9acd1bf | ||
|
|
cdc7feccc8 | ||
|
|
275fe31c04 | ||
|
|
8e9ea9e9e0 | ||
|
|
92a8453b92 | ||
|
|
7fd49b7547 | ||
|
|
8212ba8803 | ||
|
|
2bfcb6e5ab | ||
|
|
9d8cadf1fc | ||
|
|
a17809c3b9 | ||
|
|
9dbe3d003a | ||
|
|
38c476f704 | ||
|
|
90efde936a | ||
|
|
caaf1509bf | ||
|
|
9e578a4f0d | ||
|
|
f1c180ba50 | ||
|
|
8c732120bc | ||
|
|
6cf69ec6d1 | ||
|
|
67f876372c | ||
|
|
f4d658ab7e | ||
|
|
7433c3ad47 | ||
|
|
4d73e3ce78 | ||
|
|
5afa36097a | ||
|
|
afe010ed0f | ||
|
|
02f3a93b71 | ||
|
|
e9f3a43f37 | ||
|
|
8c7386fea0 | ||
|
|
d6b9da008b | ||
|
|
436142a1d8 | ||
|
|
a8445c9661 | ||
|
|
bfb9e16fcf | ||
|
|
3d729a768f | ||
|
|
2f1ed28f09 | ||
|
|
ee1b78441c | ||
|
|
2cbd674141 | ||
|
|
3182cceda4 | ||
|
|
71bcd64fb5 | ||
|
|
c2fa7282ca | ||
|
|
373fd32b0e | ||
|
|
3865835070 | ||
|
|
4be38e2dda | ||
|
|
ba286de3cb | ||
|
|
31db15f501 | ||
|
|
1f15e3b198 | ||
|
|
189883e267 | ||
|
|
ae6524bb2f | ||
|
|
ef4543df33 | ||
|
|
d46f67bf95 | ||
|
|
bbdbfb807c | ||
|
|
29aee06e76 | ||
|
|
f8587c4ed7 | ||
|
|
9c7f575569 | ||
|
|
adceff29f1 | ||
|
|
59b7fa2ebc | ||
|
|
94e3772221 | ||
|
|
8efcaf97eb | ||
|
|
eda69c23bd | ||
|
|
8c00c88818 | ||
|
|
99e07eb11c | ||
|
|
5367ce843e | ||
|
|
55d58ddb60 | ||
|
|
dc2bd9e412 | ||
|
|
7c17bba801 | ||
|
|
0c6d3ec6e0 | ||
|
|
813e807ea6 | ||
|
|
cfefa1e9b7 | ||
|
|
426ab21b69 | ||
|
|
f310e1f5ba | ||
|
|
41fd9816e8 | ||
|
|
5abe6a5875 | ||
|
|
e308b0aee1 | ||
|
|
38b1fee344 | ||
|
|
75a7cc983c | ||
|
|
d62359a009 | ||
|
|
745250942f | ||
|
|
f32ae29385 | ||
|
|
ffd47ce2dd | ||
|
|
a3ec3f368f | ||
|
|
57054caca5 | ||
|
|
965de8b742 | ||
|
|
1479848714 | ||
|
|
5fe78f7892 | ||
|
|
cdd79bc764 | ||
|
|
52b96538b7 | ||
|
|
4aa3c630df | ||
|
|
883c8c443f | ||
|
|
1d3c6d6eb8 | ||
|
|
4dcaa2c23b | ||
|
|
21e142b9a5 | ||
|
|
3cd2562626 | ||
|
|
28b5dfdb84 | ||
|
|
41bca04103 | ||
|
|
7abeb9bf00 | ||
|
|
7c4442561f | ||
|
|
7e45006300 | ||
|
|
c39cbf15be | ||
|
|
9e304fbe69 | ||
|
|
f9257cdf78 | ||
|
|
0e074e407a | ||
|
|
71cba3d1fe | ||
|
|
23f5c016cf | ||
|
|
1a82e4a294 | ||
|
|
a0be22b65f | ||
|
|
6e5626bbff | ||
|
|
6e6b81dcdf | ||
|
|
3c19eb6de2 | ||
|
|
309e48ad54 | ||
|
|
ef82567730 | ||
|
|
61cc67e4b7 | ||
|
|
0c2d1df424 | ||
|
|
35afdb1c84 | ||
|
|
a3a8caae51 | ||
|
|
5830736537 | ||
|
|
0bfdbe1e2c | ||
|
|
d41c4c6cc6 | ||
|
|
2550417804 | ||
|
|
c44db2cc35 | ||
|
|
660cb3b6ac | ||
|
|
ad12df8fcc | ||
|
|
b7ff742f84 | ||
|
|
220bfa1da5 | ||
|
|
80188edbdd | ||
|
|
0f98b3d9f2 | ||
|
|
0b9fb97557 | ||
|
|
214a912b37 | ||
|
|
990a1fe952 | ||
|
|
1ac9d52332 | ||
|
|
1fa1e7072b | ||
|
|
68dc5fe901 | ||
|
|
db9c43feea | ||
|
|
9e0c7de24e | ||
|
|
07fa660a47 | ||
|
|
734a1c63a2 | ||
|
|
e22f02f198 | ||
|
|
318e6ec067 | ||
|
|
af1303ec96 | ||
|
|
5ecf9e9202 | ||
|
|
d52f9ee87e | ||
|
|
78c9490212 | ||
|
|
2d230ce033 | ||
|
|
894dc4fc8f | ||
|
|
ec6ada4935 | ||
|
|
646cbf6d30 | ||
|
|
47d9d46304 | ||
|
|
2f16062f78 | ||
|
|
e22bfec6b6 | ||
|
|
bf24177bfd | ||
|
|
62eb3bd96c | ||
|
|
e1ebd77811 | ||
|
|
69253bc083 | ||
|
|
36b35f99a4 | ||
|
|
a91d208d10 | ||
|
|
89dd9dd9ed | ||
|
|
068da9d89f | ||
|
|
53661fefc9 | ||
|
|
d462ed3b4d | ||
|
|
4a02a79abb | ||
|
|
2ee4482d00 | ||
|
|
9f4339e7dc | ||
|
|
7e20e97ee0 | ||
|
|
86d23f42db | ||
|
|
b8299feae0 | ||
|
|
ec03eb3451 | ||
|
|
4117209b69 | ||
|
|
a870290575 | ||
|
|
e7a466b708 | ||
|
|
66ae30085b | ||
|
|
c49636c923 | ||
|
|
2f6303faef | ||
|
|
8d4c3d3a34 | ||
|
|
d212e52a20 | ||
|
|
301892bcff | ||
|
|
62892dc4e4 | ||
|
|
f08aa92da0 | ||
|
|
e5fe46a051 | ||
|
|
0c8808a57a | ||
|
|
9384ca8e20 | ||
|
|
5e536ed412 | ||
|
|
bb1fdcfa77 | ||
|
|
b91825bc73 | ||
|
|
e879ce0b12 | ||
|
|
c8735de2c1 | ||
|
|
98cf5836fd | ||
|
|
72810e9c05 | ||
|
|
3404ac174e | ||
|
|
60f59b29ed | ||
|
|
0f7ae0a660 | ||
|
|
d294e1d453 | ||
|
|
1c97f970eb | ||
|
|
8117f42634 | ||
|
|
e83404e57d | ||
|
|
499409dbc1 | ||
|
|
3da3becc24 | ||
|
|
a711fad058 | ||
|
|
2e856599b3 | ||
|
|
0119d8cbbc | ||
|
|
d8159b8be2 | ||
|
|
10442a7b4e | ||
|
|
413e2a79fb | ||
|
|
cfb0f7ffa7 | ||
|
|
7e9ef10f67 | ||
|
|
38f3d71a2f | ||
|
|
9eba533f7c | ||
|
|
9acdac02cf | ||
|
|
dfb7c1cc38 | ||
|
|
702b491981 | ||
|
|
44207c1628 | ||
|
|
85cfd10cae | ||
|
|
6ead3a5cbb | ||
|
|
e1586ea6cb | ||
|
|
72d88a2d69 | ||
|
|
3f5a1054a8 | ||
|
|
134f12f419 | ||
|
|
f3113f1a2f | ||
|
|
5d860bfc9b | ||
|
|
aa8c2937d7 | ||
|
|
38e954248c | ||
|
|
6c64f7db34 | ||
|
|
d4a9015c2b | ||
|
|
0c745d9021 | ||
|
|
6ef4b5f396 | ||
|
|
ee83302751 | ||
|
|
7e83c9231d | ||
|
|
f5e922ed92 | ||
|
|
3c41e421de | ||
|
|
4c2950a9da | ||
|
|
b8d3929dce | ||
|
|
a8b4f05418 | ||
|
|
f671fa8477 | ||
|
|
53e8674899 | ||
|
|
11049b441e | ||
|
|
6fe69f16e2 | ||
|
|
8353e981be | ||
|
|
ae76d91437 | ||
|
|
04830b787c | ||
|
|
fa844b1274 | ||
|
|
3043dcc823 | ||
|
|
7f2dd9bea1 | ||
|
|
01edf115db | ||
|
|
aebd3f30cb | ||
|
|
801a7504a6 | ||
|
|
a5ad24c0fd | ||
|
|
682b4e39fb | ||
|
|
046683ab60 | ||
|
|
29a3495c8b | ||
|
|
b2ca75e074 | ||
|
|
16748bdee9 | ||
|
|
7ef5f7004d | ||
|
|
b7ff9db6e7 | ||
|
|
953c63392c | ||
|
|
476a6ba935 | ||
|
|
6e65db5d2d | ||
|
|
30591eaf56 | ||
|
|
435587c260 | ||
|
|
6a15af599c | ||
|
|
6ba0455129 | ||
|
|
793a3e3b75 | ||
|
|
a02dad303c | ||
|
|
fc7e1c4e39 | ||
|
|
032dd3289a | ||
|
|
ab991de8a2 | ||
|
|
f14f5dc72c | ||
|
|
35615ef60e | ||
|
|
7f51f6d6ad | ||
|
|
9ddd82bc3c | ||
|
|
4292d8e0e6 | ||
|
|
5ebe984194 | ||
|
|
1712e3cbd0 | ||
|
|
87b894ea22 | ||
|
|
597460d5ea | ||
|
|
d739e44ee6 | ||
|
|
6b33fa6ddd | ||
|
|
3a9cc3d258 | ||
|
|
dd4a38ce9f | ||
|
|
4158915af3 | ||
|
|
954439af64 | ||
|
|
a74807aa86 | ||
|
|
0d4281ddfa | ||
|
|
32214ddaa6 | ||
|
|
3a43f924c6 | ||
|
|
d13d0f5848 | ||
|
|
fd83543026 | ||
|
|
607911ff27 | ||
|
|
e6f07fa0b1 | ||
|
|
1c67f4274b | ||
|
|
5efdff2a4f | ||
|
|
b15b95ee8f | ||
|
|
b0a351f55a | ||
|
|
1ea83e5774 | ||
|
|
4244dfe0a2 | ||
|
|
e7e9db8cee | ||
|
|
6b53ac6790 | ||
|
|
9872d1c997 | ||
|
|
31b7d78516 | ||
|
|
36dcf15ebc | ||
|
|
56021c1af9 | ||
|
|
1d8dd53995 | ||
|
|
7375c8a058 | ||
|
|
f61d5c24ac | ||
|
|
7c17c11a04 | ||
|
|
d4f5db4b8a | ||
|
|
be4f88c811 | ||
|
|
6f150a343b | ||
|
|
30ea3a26d0 | ||
|
|
cb3f554e38 | ||
|
|
3999837279 | ||
|
|
9d3ad08a82 | ||
|
|
a21843f974 | ||
|
|
fd2bab9b11 | ||
|
|
7d8134ca36 | ||
|
|
fc287b2943 | ||
|
|
4b1a419883 | ||
|
|
002587824e | ||
|
|
96241294bb | ||
|
|
9f85e2769c | ||
|
|
cf62f931d9 | ||
|
|
1af202bf10 | ||
|
|
98331a662f | ||
|
|
2dce2d0d63 | ||
|
|
80bca72915 | ||
|
|
2a0c73d0e5 | ||
|
|
ea97ea4c47 | ||
|
|
081f3e43c0 | ||
|
|
9b3d89db04 | ||
|
|
f151daa2f9 | ||
|
|
4b062a4010 | ||
|
|
d7817793c3 | ||
|
|
3f2cc10bfe | ||
|
|
9c07649287 | ||
|
|
47f931c8b2 | ||
|
|
61e2caf818 | ||
|
|
ad97969e93 | ||
|
|
25ca8dc835 | ||
|
|
a41c6d32c3 | ||
|
|
f2e34bd172 | ||
|
|
5bbd1d20cf | ||
|
|
ff44938f9f | ||
|
|
414aae50c2 | ||
|
|
36160a81fb | ||
|
|
36a4f662b2 | ||
|
|
3d406e5213 | ||
|
|
61237d4c08 | ||
|
|
341c6b2929 | ||
|
|
4f7a2dfb50 | ||
|
|
0542c12aae | ||
|
|
203cd6ecf2 | ||
|
|
2adc193421 | ||
|
|
fe2ebeef25 | ||
|
|
e9cd90f52e | ||
|
|
d973fa129b | ||
|
|
4fa65f3853 | ||
|
|
f478fee5fb | ||
|
|
4b4022358a | ||
|
|
413c33274d | ||
|
|
e13714e400 | ||
|
|
bcd6ac885d | ||
|
|
512dfd6aaf | ||
|
|
d95f304073 | ||
|
|
18c153ef8a | ||
|
|
bb60e06b88 | ||
|
|
0ae2a2ded8 | ||
|
|
811f1b19bd | ||
|
|
a0b739c259 | ||
|
|
cbda203f23 | ||
|
|
d7a5eab7d5 | ||
|
|
e51f0cec94 | ||
|
|
c6f8dc2482 | ||
|
|
e3387386e0 | ||
|
|
520bfa5c42 | ||
|
|
77c73e8801 | ||
|
|
0a46111bb2 | ||
|
|
551018136b | ||
|
|
48be0c1bd0 | ||
|
|
1c983629b5 | ||
|
|
65160f626d | ||
|
|
1445a655fe | ||
|
|
cf8adfe5d3 | ||
|
|
cf624ebb7b | ||
|
|
c9a81e5241 | ||
|
|
d7e47f413f | ||
|
|
28b62cfb71 |
@@ -12,124 +12,103 @@
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "3.2",
|
||||
"branchName": "3.2.x",
|
||||
"slug": "3.2",
|
||||
"name": "3.6",
|
||||
"branchName": "3.6.x",
|
||||
"slug": "3.6",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "3.1",
|
||||
"branchName": "3.1.x",
|
||||
"slug": "3.1",
|
||||
"name": "3.5",
|
||||
"branchName": "3.5.x",
|
||||
"slug": "3.5",
|
||||
"current": true
|
||||
},
|
||||
{
|
||||
"name": "3.4",
|
||||
"slug": "3.4",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "3.3",
|
||||
"slug": "3.3",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "3.2",
|
||||
"slug": "3.2",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "3.1",
|
||||
"slug": "3.1",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "3.0",
|
||||
"branchName": "3.0.x",
|
||||
"slug": "3.0",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.21",
|
||||
"branchName": "2.21.x",
|
||||
"slug": "2.21",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.20",
|
||||
"branchName": "2.20.x",
|
||||
"slug": "2.20",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.19",
|
||||
"branchName": "2.19.x",
|
||||
"slug": "2.19",
|
||||
"maintained": true
|
||||
},
|
||||
{
|
||||
"name": "2.19",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"name": "2.9",
|
||||
"branchName": "2.9.x",
|
||||
"slug": "2.9",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.8",
|
||||
"branchName": "2.8.x",
|
||||
"slug": "2.8",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.7",
|
||||
"branchName": "2.7",
|
||||
"slug": "2.7",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.6",
|
||||
"branchName": "2.6",
|
||||
"slug": "2.6",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.5",
|
||||
"branchName": "2.5",
|
||||
"slug": "2.5",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.4",
|
||||
"branchName": "2.4",
|
||||
"slug": "2.4",
|
||||
"maintained": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -19,5 +19,3 @@ phpstan-baseline.neon export-ignore
|
||||
phpstan-dbal2.neon export-ignore
|
||||
phpstan-params.neon export-ignore
|
||||
phpstan-persistence2.neon export-ignore
|
||||
psalm.xml export-ignore
|
||||
psalm-baseline.xml export-ignore
|
||||
|
||||
37
.github/ISSUE_TEMPLATE/BC_Break.md
vendored
37
.github/ISSUE_TEMPLATE/BC_Break.md
vendored
@@ -1,37 +0,0 @@
|
||||
---
|
||||
name: 💥 BC Break
|
||||
about: Have you encountered an issue during upgrade? 💣
|
||||
---
|
||||
|
||||
<!--
|
||||
Before reporting a BC break, please consult the upgrading document to make sure it's not an expected change: https://github.com/doctrine/orm/blob/2.9.x/UPGRADE.md
|
||||
-->
|
||||
|
||||
### BC Break Report
|
||||
|
||||
<!-- Fill in the relevant information below to help triage your issue. -->
|
||||
|
||||
| Q | A
|
||||
|------------ | ------
|
||||
| BC Break | yes
|
||||
| Version | x.y.z
|
||||
|
||||
#### Summary
|
||||
|
||||
<!-- Provide a summary describing the problem you are experiencing. -->
|
||||
|
||||
#### Previous behavior
|
||||
|
||||
<!-- What was the previous (working) behavior? -->
|
||||
|
||||
#### Current behavior
|
||||
|
||||
<!-- What is the current (broken) behavior? -->
|
||||
|
||||
#### How to reproduce
|
||||
|
||||
<!--
|
||||
Provide steps to reproduce the BC break.
|
||||
If possible, also add a code snippet with relevant configuration, entity mappings, DQL etc.
|
||||
Adding a failing Unit or Functional Test would help us a lot - you can submit it in a Pull Request separately, referencing this bug report.
|
||||
-->
|
||||
34
.github/ISSUE_TEMPLATE/Bug.md
vendored
34
.github/ISSUE_TEMPLATE/Bug.md
vendored
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: 🐞 Bug Report
|
||||
about: Something is broken? 🔨
|
||||
---
|
||||
|
||||
### Bug Report
|
||||
|
||||
<!-- Fill in the relevant information below to help triage your issue. -->
|
||||
|
||||
| Q | A
|
||||
|------------ | ------
|
||||
| BC Break | yes/no
|
||||
| Version | x.y.z
|
||||
|
||||
#### Summary
|
||||
|
||||
<!-- Provide a summary describing the problem you are experiencing. -->
|
||||
|
||||
#### Current behavior
|
||||
|
||||
<!-- What is the current (buggy) behavior? -->
|
||||
|
||||
#### How to reproduce
|
||||
|
||||
<!--
|
||||
Provide steps to reproduce the bug.
|
||||
If possible, also add a code snippet with relevant configuration, entity mappings, DQL etc.
|
||||
Adding a failing Unit or Functional Test would help us a lot - you can submit one in a Pull Request separately, referencing this bug report.
|
||||
-->
|
||||
|
||||
#### Expected behavior
|
||||
|
||||
<!-- What was the expected (correct) behavior? -->
|
||||
|
||||
18
.github/ISSUE_TEMPLATE/Feature_Request.md
vendored
18
.github/ISSUE_TEMPLATE/Feature_Request.md
vendored
@@ -1,18 +0,0 @@
|
||||
---
|
||||
name: 🎉 Feature Request
|
||||
about: You have a neat idea that should be implemented? 🎩
|
||||
---
|
||||
|
||||
### Feature Request
|
||||
|
||||
<!-- Fill in the relevant information below to help triage your issue. -->
|
||||
|
||||
| Q | A
|
||||
|------------ | ------
|
||||
| New Feature | yes
|
||||
| RFC | yes/no
|
||||
| BC Break | yes/no
|
||||
|
||||
#### Summary
|
||||
|
||||
<!-- Provide a summary of the feature you would like to see implemented. -->
|
||||
6
.github/ISSUE_TEMPLATE/Support_Question.md
vendored
6
.github/ISSUE_TEMPLATE/Support_Question.md
vendored
@@ -1,6 +0,0 @@
|
||||
---
|
||||
name: ❓ Support Question
|
||||
about: Have a problem that you can't figure out? 🤔
|
||||
---
|
||||
|
||||
Please use https://github.com/doctrine/orm/discussions instead.
|
||||
9
.github/dependabot.yml
vendored
Normal file
9
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
labels:
|
||||
- "CI"
|
||||
target-branch: "2.20.x"
|
||||
2
.github/workflows/coding-standards.yml
vendored
2
.github/workflows/coding-standards.yml
vendored
@@ -24,4 +24,4 @@ on:
|
||||
|
||||
jobs:
|
||||
coding-standards:
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@5.0.1"
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.3.0"
|
||||
|
||||
110
.github/workflows/continuous-integration.yml
vendored
110
.github/workflows/continuous-integration.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: "Continuous Integration"
|
||||
name: "CI"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -9,7 +9,6 @@ on:
|
||||
- ci/**
|
||||
- composer.*
|
||||
- src/**
|
||||
- phpunit.xml.dist
|
||||
- tests/**
|
||||
push:
|
||||
branches:
|
||||
@@ -19,7 +18,6 @@ on:
|
||||
- ci/**
|
||||
- composer.*
|
||||
- src/**
|
||||
- phpunit.xml.dist
|
||||
- tests/**
|
||||
|
||||
env:
|
||||
@@ -33,33 +31,39 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "7.2"
|
||||
- "7.3"
|
||||
- "7.4"
|
||||
- "8.0"
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3.7"
|
||||
extension:
|
||||
- "sqlite3"
|
||||
- "pdo_sqlite"
|
||||
proxy:
|
||||
- "common"
|
||||
deps:
|
||||
- "highest"
|
||||
native_lazy:
|
||||
- "0"
|
||||
include:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
extension: "pdo_sqlite"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "3@dev"
|
||||
dbal-version: "4@dev"
|
||||
extension: "pdo_sqlite"
|
||||
native_lazy: "0"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "default"
|
||||
dbal-version: "4@dev"
|
||||
extension: "sqlite3"
|
||||
native_lazy: "0"
|
||||
- php-version: "8.1"
|
||||
dbal-version: "default"
|
||||
proxy: "lazy-ghost"
|
||||
deps: "lowest"
|
||||
extension: "pdo_sqlite"
|
||||
native_lazy: "0"
|
||||
- php-version: "8.4"
|
||||
dbal-version: "default"
|
||||
deps: "highest"
|
||||
extension: "pdo_sqlite"
|
||||
native_lazy: "1"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
@@ -83,23 +87,24 @@ jobs:
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
dependency-versions: "${{ matrix.deps }}"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage-no-cache.xml"
|
||||
env:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 0
|
||||
ORM_PROXY_IMPLEMENTATION: "${{ matrix.proxy }}"
|
||||
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"
|
||||
env:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 1
|
||||
ORM_PROXY_IMPLEMENTATION: "${{ matrix.proxy }}"
|
||||
ENABLE_NATIVE_LAZY_OBJECTS: ${{ matrix.native_lazy }}
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.proxy }}-coverage"
|
||||
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.deps }}-${{ matrix.native_lazy }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
|
||||
|
||||
@@ -113,21 +118,22 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
- "3.7"
|
||||
postgres-version:
|
||||
- "15"
|
||||
- "17"
|
||||
extension:
|
||||
- pdo_pgsql
|
||||
- pgsql
|
||||
include:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "4@dev"
|
||||
postgres-version: "14"
|
||||
extension: pdo_pgsql
|
||||
- php-version: "8.2"
|
||||
dbal-version: "default"
|
||||
dbal-version: "3.7"
|
||||
postgres-version: "9.6"
|
||||
extension: pdo_pgsql
|
||||
|
||||
@@ -186,19 +192,16 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
- "3.7"
|
||||
- "4@dev"
|
||||
mariadb-version:
|
||||
- "11.4"
|
||||
extension:
|
||||
- "mysqli"
|
||||
- "pdo_mysql"
|
||||
include:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
mariadb-version: "10.6"
|
||||
extension: "pdo_mysql"
|
||||
|
||||
services:
|
||||
mariadb:
|
||||
@@ -256,9 +259,10 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
- "3.7"
|
||||
mysql-version:
|
||||
- "5.7"
|
||||
- "8.0"
|
||||
@@ -266,8 +270,12 @@ jobs:
|
||||
- "mysqli"
|
||||
- "pdo_mysql"
|
||||
include:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "4@dev"
|
||||
mysql-version: "8.0"
|
||||
extension: "mysqli"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "4@dev"
|
||||
mysql-version: "8.0"
|
||||
extension: "pdo_mysql"
|
||||
|
||||
@@ -322,43 +330,11 @@ jobs:
|
||||
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
|
||||
|
||||
phpunit-lower-php-versions:
|
||||
name: "PHPUnit with SQLite"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "7.1"
|
||||
deps:
|
||||
- "highest"
|
||||
- "lowest"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
ini-values: "zend.assertions=1, apc.enable_cli=1"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "${{ matrix.deps }}"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_sqlite.xml"
|
||||
|
||||
|
||||
upload_coverage:
|
||||
name: "Upload coverage to Codecov"
|
||||
runs-on: "ubuntu-22.04"
|
||||
# Only run on PRs from forks
|
||||
if: "github.event.pull_request.head.repo.full_name != github.repository"
|
||||
needs:
|
||||
- "phpunit-smoke-check"
|
||||
- "phpunit-postgres"
|
||||
@@ -377,7 +353,7 @@ jobs:
|
||||
path: "reports"
|
||||
|
||||
- name: "Upload to Codecov"
|
||||
uses: "codecov/codecov-action@v4"
|
||||
uses: "codecov/codecov-action@v5"
|
||||
with:
|
||||
directory: reports
|
||||
env:
|
||||
|
||||
43
.github/workflows/documentation.yml
vendored
43
.github/workflows/documentation.yml
vendored
@@ -5,45 +5,16 @@ on:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/documentation.yml
|
||||
- docs/**
|
||||
- ".github/workflows/documentation.yml"
|
||||
- "docs/**"
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/documentation.yml
|
||||
- docs/**
|
||||
- ".github/workflows/documentation.yml"
|
||||
- "docs/**"
|
||||
|
||||
jobs:
|
||||
validate-with-guides:
|
||||
name: "Validate documentation with phpDocumentor/guides"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.3"
|
||||
|
||||
- name: "Remove existing composer file"
|
||||
run: "rm composer.json"
|
||||
|
||||
- name: "Require phpdocumentor/guides-cli"
|
||||
run: "composer require --dev phpdocumentor/guides-cli --no-update"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
- name: "Add orphan metadata where needed"
|
||||
run: |
|
||||
printf '%s\n\n%s\n' ":orphan:" "$(cat docs/en/sidebar.rst)" > docs/en/sidebar.rst
|
||||
printf '%s\n\n%s\n' ":orphan:" "$(cat docs/en/reference/installation.rst)" > docs/en/reference/installation.rst
|
||||
|
||||
- name: "Run guides-cli"
|
||||
run: "vendor/bin/guides -vvv --no-progress docs/en 2>&1 | grep -v 'No template found for rendering directive' | ( ! grep WARNING )"
|
||||
documentation:
|
||||
name: "Documentation"
|
||||
uses: "doctrine/.github/.github/workflows/documentation.yml@7.3.0"
|
||||
|
||||
2
.github/workflows/phpbench.yml
vendored
2
.github/workflows/phpbench.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "7.4"
|
||||
- "8.1"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@5.0.1"
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.3.0"
|
||||
secrets:
|
||||
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
|
||||
24
.github/workflows/stale.yml
vendored
Normal file
24
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: 'Close stale pull requests'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
stale-pr-message: >
|
||||
There hasn't been any activity on this pull request in the past 90 days, so
|
||||
it has been marked as stale and it will be closed automatically if no
|
||||
further activity occurs in the next 7 days.
|
||||
|
||||
If you want to continue working on it, please leave a comment.
|
||||
|
||||
close-pr-message: >
|
||||
This pull request was closed due to inactivity.
|
||||
|
||||
days-before-stale: -1
|
||||
days-before-pr-stale: 90
|
||||
days-before-pr-close: 7
|
||||
79
.github/workflows/static-analysis.yml
vendored
79
.github/workflows/static-analysis.yml
vendored
@@ -9,7 +9,6 @@ on:
|
||||
- composer.*
|
||||
- src/**
|
||||
- phpstan*
|
||||
- psalm*
|
||||
- tests/StaticAnalysis/**
|
||||
push:
|
||||
branches:
|
||||
@@ -19,85 +18,39 @@ on:
|
||||
- composer.*
|
||||
- src/**
|
||||
- phpstan*
|
||||
- psalm*
|
||||
- tests/StaticAnalysis/**
|
||||
|
||||
jobs:
|
||||
static-analysis-phpstan:
|
||||
name: "Static Analysis with PHPStan"
|
||||
runs-on: "ubuntu-22.04"
|
||||
name: Static Analysis with PHPStan
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
dbal-version:
|
||||
- "default"
|
||||
persistence-version:
|
||||
- "default"
|
||||
include:
|
||||
- dbal-version: "2.13"
|
||||
persistence-version: "default"
|
||||
- dbal-version: "default"
|
||||
persistence-version: "2.5"
|
||||
- dbal-version: default
|
||||
config: phpstan.neon
|
||||
- dbal-version: 3.8.2
|
||||
config: phpstan-dbal3.neon
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.3"
|
||||
coverage: none
|
||||
php-version: "8.4"
|
||||
tools: cs2pr
|
||||
|
||||
- name: "Require specific DBAL version"
|
||||
- name: Require specific DBAL version
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Require specific persistence version"
|
||||
run: "composer require doctrine/persistence ^$([ ${{ matrix.persistence-version }} = default ] && echo '3.1' || echo ${{ matrix.persistence-version }}) --no-update"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
- name: Install dependencies with Composer
|
||||
uses: ramsey/composer-install@v2
|
||||
|
||||
- name: "Run a static analysis with phpstan/phpstan"
|
||||
run: "vendor/bin/phpstan analyse"
|
||||
if: "${{ matrix.dbal-version == 'default' && matrix.persistence-version == 'default'}}"
|
||||
|
||||
- name: "Run a static analysis with phpstan/phpstan"
|
||||
run: "vendor/bin/phpstan analyse -c phpstan-dbal2.neon"
|
||||
if: "${{ matrix.dbal-version == '2.13' }}"
|
||||
|
||||
- name: "Run a static analysis with phpstan/phpstan"
|
||||
run: "vendor/bin/phpstan analyse -c phpstan-persistence2.neon"
|
||||
if: "${{ matrix.dbal-version == 'default' && matrix.persistence-version != 'default'}}"
|
||||
|
||||
static-analysis-psalm:
|
||||
name: "Static Analysis with Psalm"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.3"
|
||||
|
||||
- name: "Require specific persistence version"
|
||||
run: "composer require doctrine/persistence ^3.1 --no-update"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
- name: "Run a static analysis with vimeo/psalm"
|
||||
run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"
|
||||
- name: Run static analysis with phpstan/phpstan
|
||||
run: "vendor/bin/phpstan analyse -c ${{ matrix.config }} --error-format=checkstyle | cs2pr"
|
||||
|
||||
21
.github/workflows/website-schema.yml
vendored
Normal file
21
.github/workflows/website-schema.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
name: "Website config validation"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- ".doctrine-project.json"
|
||||
- ".github/workflows/website-schema.yml"
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- ".doctrine-project.json"
|
||||
- ".github/workflows/website-schema.yml"
|
||||
|
||||
jobs:
|
||||
json-validate:
|
||||
name: "Validate JSON schema"
|
||||
uses: "doctrine/.github/.github/workflows/website-schema.yml@7.1.0"
|
||||
@@ -57,7 +57,7 @@ sqlite database.
|
||||
Tips for creating unit tests:
|
||||
|
||||
1. If you put a test into the `Ticket` namespace as described above, put the testcase and all entities into the same class.
|
||||
See `https://github.com/doctrine/orm/tree/2.8.x/tests/Tests/ORM/Functional/Ticket/DDC2306Test.php` for an
|
||||
See `https://github.com/doctrine/orm/tree/3.0.x/tests/Tests/ORM/Functional/Ticket/DDC2306Test.php` for an
|
||||
example.
|
||||
|
||||
## Getting merged
|
||||
|
||||
39
README.md
39
README.md
@@ -1,11 +1,9 @@
|
||||
| [4.0.x][4.0] | [3.2.x][3.2] | [3.1.x][3.1] | [2.20.x][2.20] | [2.19.x][2.19] |
|
||||
| [4.0.x][4.0] | [3.6.x][3.6] | [3.5.x][3.5] | [2.21.x][2.21] | [2.20.x][2.20] |
|
||||
|:------------------------------------------------------:|:------------------------------------------------------:|:------------------------------------------------------:|:--------------------------------------------------------:|:--------------------------------------------------------:|
|
||||
| [![Build status][4.0 image]][4.0] | [![Build status][3.2 image]][3.2] | [![Build status][3.1 image]][3.1] | [![Build status][2.20 image]][2.20] | [![Build status][2.19 image]][2.19] |
|
||||
| [![Coverage Status][4.0 coverage image]][4.0 coverage] | [![Coverage Status][3.2 coverage image]][3.2 coverage] | [![Coverage Status][3.1 coverage image]][3.1 coverage] | [![Coverage Status][2.20 coverage image]][2.20 coverage] | [![Coverage Status][2.19 coverage image]][2.19 coverage] |
|
||||
| [![Build status][4.0 image]][4.0 workflow] | [![Build status][3.6 image]][3.6 workflow] | [![Build status][3.5 image]][3.5 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.6 coverage image]][3.6 coverage] | [![Coverage Status][3.5 coverage image]][3.5 coverage] | [![Coverage Status][2.21 coverage image]][2.21 coverage] | [![Coverage Status][2.20 coverage image]][2.20 coverage] |
|
||||
|
||||
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
|
||||
|
||||
Doctrine ORM is an object-relational mapper for PHP 7.1+ that provides transparent persistence
|
||||
Doctrine ORM is an object-relational mapper for PHP 8.1+ that provides transparent persistence
|
||||
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
|
||||
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
|
||||
@@ -20,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.2 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.2.x
|
||||
[3.2]: https://github.com/doctrine/orm/tree/3.2.x
|
||||
[3.2 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.2.x/graph/badge.svg
|
||||
[3.2 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.2.x
|
||||
[3.1 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.1.x
|
||||
[3.1]: https://github.com/doctrine/orm/tree/3.1.x
|
||||
[3.1 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.1.x/graph/badge.svg
|
||||
[3.1 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.1.x
|
||||
[3.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
|
||||
[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 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A3.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
|
||||
[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
|
||||
[2.19 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.19.x
|
||||
[2.19]: https://github.com/doctrine/orm/tree/2.19.x
|
||||
[2.19 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.19.x/graph/badge.svg
|
||||
[2.19 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.19.x
|
||||
|
||||
882
UPGRADE.md
882
UPGRADE.md
@@ -1,3 +1,885 @@
|
||||
# Upgrade to 3.5
|
||||
|
||||
## 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
|
||||
|
||||
This feature was introduced in 3.4.0, and introduces several issues, so we
|
||||
decide to remove it before it is used too widely.
|
||||
|
||||
# Upgrade to 3.4
|
||||
|
||||
## Discriminator Map class duplicates
|
||||
|
||||
Using the same class several times in a discriminator map is deprecated.
|
||||
In 4.0, this will be an error.
|
||||
|
||||
## `Doctrine\ORM\Mapping\ClassMetadata::$reflFields` deprecated
|
||||
|
||||
To better support property hooks and lazy proxies in the future, `$reflFields` had to
|
||||
be deprecated because we cannot use the PHP internal reflection API directly anymore.
|
||||
|
||||
The property was changed from an array to an object of type `LegacyReflectionFields`
|
||||
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
|
||||
|
||||
## Deprecate `DatabaseDriver`
|
||||
|
||||
The class `Doctrine\ORM\Mapping\Driver\DatabaseDriver` is deprecated without replacement.
|
||||
|
||||
## Add `Doctrine\ORM\Query\OutputWalker` interface, deprecate `Doctrine\ORM\Query\SqlWalker::getExecutor()`
|
||||
|
||||
Output walkers should implement the new `\Doctrine\ORM\Query\OutputWalker` interface and create
|
||||
`Doctrine\ORM\Query\Exec\SqlFinalizer` instances instead of `Doctrine\ORM\Query\Exec\AbstractSqlExecutor`s.
|
||||
The output walker must not base its workings on the query `firstResult`/`maxResult` values, so that the
|
||||
`SqlFinalizer` can be kept in the query cache and used regardless of the actual `firstResult`/`maxResult` values.
|
||||
Any operation dependent on `firstResult`/`maxResult` should take place within the `SqlFinalizer::createExecutor()`
|
||||
method. Details can be found at https://github.com/doctrine/orm/pull/11188.
|
||||
|
||||
|
||||
# Upgrade to 3.2
|
||||
|
||||
## Deprecate the `NotSupported` exception
|
||||
|
||||
The class `Doctrine\ORM\Exception\NotSupported` is deprecated without replacement.
|
||||
|
||||
## Deprecate remaining `Serializable` implementation
|
||||
|
||||
Relying on `SequenceGenerator` implementing the `Serializable` is deprecated
|
||||
because that interface won't be implemented in ORM 4 anymore.
|
||||
|
||||
The following methods are deprecated:
|
||||
|
||||
* `SequenceGenerator::serialize()`
|
||||
* `SequenceGenerator::unserialize()`
|
||||
|
||||
## `orm:schema-tool:update` option `--complete` is deprecated
|
||||
|
||||
That option behaves as a no-op, and is deprecated. It will be removed in 4.0.
|
||||
|
||||
## Deprecate properties `$indexes` and `$uniqueConstraints` of `Doctrine\ORM\Mapping\Table`
|
||||
|
||||
The properties `$indexes` and `$uniqueConstraints` have been deprecated 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.1
|
||||
|
||||
## Deprecate `Doctrine\ORM\Mapping\ReflectionEnumProperty`
|
||||
|
||||
This class is deprecated and will be removed in 4.0.
|
||||
Instead, use `Doctrine\Persistence\Reflection\EnumReflectionProperty` from
|
||||
`doctrine/persistence`.
|
||||
|
||||
## Deprecate passing null to `ClassMetadata::fullyQualifiedClassName()`
|
||||
|
||||
Passing `null` to `Doctrine\ORM\ClassMetadata::fullyQualifiedClassName()` is
|
||||
deprecated and will no longer be possible in 4.0.
|
||||
|
||||
## Deprecate array access
|
||||
|
||||
Using array access on instances of the following classes is deprecated:
|
||||
|
||||
- `Doctrine\ORM\Mapping\DiscriminatorColumnMapping`
|
||||
- `Doctrine\ORM\Mapping\EmbedClassMapping`
|
||||
- `Doctrine\ORM\Mapping\FieldMapping`
|
||||
- `Doctrine\ORM\Mapping\JoinColumnMapping`
|
||||
- `Doctrine\ORM\Mapping\JoinTableMapping`
|
||||
|
||||
# Upgrade to 3.0
|
||||
|
||||
## BC BREAK: Calling `ClassMetadata::getAssociationMappedByTargetField()` with the owning side of an association now throws an exception
|
||||
|
||||
Previously, calling
|
||||
`Doctrine\ORM\Mapping\ClassMetadata::getAssociationMappedByTargetField()` with
|
||||
the owning side of an association returned `null`, which was undocumented, and
|
||||
wrong according to the phpdoc of the parent method.
|
||||
|
||||
If you do not know whether you are on the owning or inverse side of an association,
|
||||
you can use `Doctrine\ORM\Mapping\ClassMetadata::isAssociationInverseSide()`
|
||||
to find out.
|
||||
|
||||
## BC BREAK: `Doctrine\ORM\Proxy\Autoloader` no longer extends `Doctrine\Common\Proxy\Autoloader`
|
||||
|
||||
Make sure to use the former when writing a type declaration or an `instanceof` check.
|
||||
|
||||
## Minor BC BREAK: Changed order of arguments passed to `OneToOne`, `ManyToOne` and `Index` mapping PHP attributes
|
||||
|
||||
To keep PHP mapping attributes consistent, order of arguments passed to above attributes has been changed
|
||||
so `$targetEntity` is a first argument now. This change affects only non-named arguments usage.
|
||||
|
||||
## BC BREAK: AUTO keyword for identity generation defaults to IDENTITY for PostgreSQL when using `doctrine/dbal` 4
|
||||
|
||||
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`.
|
||||
* 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
|
||||
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
|
||||
use Doctrine\ORM\Configuration;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
assert($configuration instanceof Configuration);
|
||||
$configuration->setIdentityGenerationPreferences([
|
||||
PostgreSQLPlatform::CLASS => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
|
||||
]);
|
||||
```
|
||||
|
||||
## BC BREAK: Throw exceptions when using illegal attributes on Embeddable
|
||||
|
||||
There are only a few attributes allowed on an embeddable such as `#[Column]` or
|
||||
`#[Embedded]`. Previously all others that target entity classes where ignored,
|
||||
now they throw an exception.
|
||||
|
||||
## BC BREAK: Partial objects are removed
|
||||
|
||||
WARNING: This was relaxed in ORM 3.2 when partial was re-allowed for array-hydration.
|
||||
|
||||
- The `PARTIAL` keyword in DQL no longer exists (reintroduced in ORM 3.2)
|
||||
- `Doctrine\ORM\Query\AST\PartialObjectExpression` is removed. (reintroduced in ORM 3.2)
|
||||
- `Doctrine\ORM\Query\SqlWalker::HINT_PARTIAL` (reintroduced in ORM 3.2) and
|
||||
`Doctrine\ORM\Query::HINT_FORCE_PARTIAL_LOAD` are removed.
|
||||
- `Doctrine\ORM\EntityManager*::getPartialReference()` is removed.
|
||||
|
||||
## BC BREAK: Enforce ArrayCollection Type on `\Doctrine\ORM\QueryBuilder::setParameters(ArrayCollection $parameters)`
|
||||
|
||||
The argument $parameters can no longer be a key=>value array. Only ArrayCollection types are allowed.
|
||||
|
||||
### Before
|
||||
|
||||
```php
|
||||
$qb = $em->createQueryBuilder()
|
||||
->select('u')
|
||||
->from('User', 'u')
|
||||
->where('u.id = :user_id1 OR u.id = :user_id2')
|
||||
->setParameters(array(
|
||||
'user_id1' => 1,
|
||||
'user_id2' => 2
|
||||
));
|
||||
```
|
||||
|
||||
### After
|
||||
|
||||
```php
|
||||
$qb = $em->createQueryBuilder()
|
||||
->select('u')
|
||||
->from('User', 'u')
|
||||
->where('u.id = :user_id1 OR u.id = :user_id2')
|
||||
->setParameters(new ArrayCollection(array(
|
||||
new Parameter('user_id1', 1),
|
||||
new Parameter('user_id2', 2)
|
||||
)));
|
||||
```
|
||||
|
||||
## BC BREAK: `Doctrine\ORM\Persister\Entity\EntityPersister::executeInserts()` return type changed to `void`
|
||||
|
||||
Implementors should adapt to the new signature, and should call
|
||||
`UnitOfWork::assignPostInsertId()` for each entry in the previously returned
|
||||
array.
|
||||
|
||||
## BC BREAK: `Doctrine\ORM\Proxy\ProxyFactory` no longer extends abstract factory from `doctrine/common`
|
||||
|
||||
It is no longer possible to call methods, constants or properties inherited
|
||||
from that class on a `ProxyFactory` instance.
|
||||
|
||||
`Doctrine\ORM\Proxy\ProxyFactory::createProxyDefinition()` and
|
||||
`Doctrine\ORM\Proxy\ProxyFactory::resetUninitializedProxy()` are removed as well.
|
||||
|
||||
## BC BREAK: lazy ghosts are enabled unconditionally
|
||||
|
||||
`Doctrine\ORM\Configuration::setLazyGhostObjectEnabled()` and
|
||||
`Doctrine\ORM\Configuration::isLazyGhostObjectEnabled()` are now no-ops and
|
||||
will be deprecated in 3.1.0
|
||||
|
||||
## BC BREAK: collisions in identity map are unconditionally rejected
|
||||
|
||||
`Doctrine\ORM\Configuration::setRejectIdCollisionInIdentityMap()` and
|
||||
`Doctrine\ORM\Configuration::isRejectIdCollisionInIdentityMapEnabled()` are now
|
||||
no-ops and will be deprecated in 3.1.0.
|
||||
|
||||
## BC BREAK: Lifecycle callback mapping on embedded classes is now explicitly forbidden
|
||||
|
||||
Lifecycle callback mapping on embedded classes produced no effect, and is now
|
||||
explicitly forbidden to point out mistakes.
|
||||
|
||||
## BC BREAK: The `NOTIFY` change tracking policy is removed
|
||||
|
||||
You should use `DEFERRED_EXPLICIT` instead.
|
||||
|
||||
## BC BREAK: `Mapping\Driver\XmlDriver::__construct()` third argument is now enabled by default
|
||||
|
||||
The third argument to
|
||||
`Doctrine\ORM\Mapping\Driver\XmlDriver::__construct()` was introduced to
|
||||
let users opt-in to XML validation, that is now always enabled by default.
|
||||
|
||||
As a consequence, the same goes for
|
||||
`Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver`, and for
|
||||
`Doctrine\ORM\ORMSetup::createXMLMetadataConfiguration()`.
|
||||
|
||||
## BC BREAK: `Mapping\Driver\AttributeDriver::__construct()` second argument is now a no-op
|
||||
|
||||
The second argument to
|
||||
`Doctrine\ORM\Mapping\Driver\AttributeDriver::__construct()` was introduced to
|
||||
let users opt-in to a new behavior, that is now always enforced, regardless of
|
||||
the value of that argument.
|
||||
|
||||
## BC BREAK: `Query::setDQL()` and `Query::setFirstResult()` no longer accept `null`
|
||||
|
||||
The `$dqlQuery` argument of `Doctrine\ORM\Query::setDQL()` must always be a
|
||||
string.
|
||||
|
||||
The `$firstResult` argument of `Doctrine\ORM\Query::setFirstResult()` must
|
||||
always be an integer.
|
||||
|
||||
## BC BREAK: `orm:schema-tool:update` option `--complete` is now a no-op
|
||||
|
||||
`orm:schema-tool:update` now behaves as if `--complete` was provided,
|
||||
regardless of whether it is provided or not.
|
||||
|
||||
## BC BREAK: Removed `Doctrine\ORM\Proxy\Proxy` interface.
|
||||
|
||||
Use `Doctrine\Persistence\Proxy` instead to check whether proxies are initialized.
|
||||
|
||||
## BC BREAK: Overriding fields or associations declared in other than mapped superclasses
|
||||
|
||||
As stated in the documentation, fields and associations may only be overridden when being inherited
|
||||
from mapped superclasses. Overriding them for parent entity classes now throws a `MappingException`.
|
||||
|
||||
## BC BREAK: Undeclared entity inheritance now throws a `MappingException`
|
||||
|
||||
As soon as an entity class inherits from another entity class, inheritance has to
|
||||
be declared by adding the appropriate configuration for the root entity.
|
||||
|
||||
## Removed `getEntityManager()` in `Doctrine\ORM\Event\OnClearEventArgs` and `Doctrine\ORM\Event\*FlushEventArgs`
|
||||
|
||||
Use `getObjectManager()` instead.
|
||||
|
||||
## BC BREAK: Removed `Doctrine\ORM\Mapping\ClassMetadataInfo` class
|
||||
|
||||
Use `Doctrine\ORM\Mapping\ClassMetadata` instead.
|
||||
|
||||
## BC BREAK: Removed `Doctrine\ORM\Event\LifecycleEventArgs` class.
|
||||
|
||||
Use one of the dedicated event classes instead:
|
||||
|
||||
* `Doctrine\ORM\Event\PrePersistEventArgs`
|
||||
* `Doctrine\ORM\Event\PreUpdateEventArgs`
|
||||
* `Doctrine\ORM\Event\PreRemoveEventArgs`
|
||||
* `Doctrine\ORM\Event\PostPersistEventArgs`
|
||||
* `Doctrine\ORM\Event\PostUpdateEventArgs`
|
||||
* `Doctrine\ORM\Event\PostRemoveEventArgs`
|
||||
* `Doctrine\ORM\Event\PostLoadEventArgs`
|
||||
|
||||
## BC BREAK: Removed `AttributeDriver::$entityAnnotationClasses` and `AttributeDriver::getReader()`
|
||||
|
||||
* If you need to change the behavior of `AttributeDriver::isTransient()`,
|
||||
override that method instead.
|
||||
* The attribute reader is internal to the driver and should not be accessed from outside.
|
||||
|
||||
## BC BREAK: Removed `Doctrine\ORM\Query\AST\InExpression`
|
||||
|
||||
The AST parser will create a `InListExpression` or a `InSubselectExpression` when
|
||||
encountering an `IN ()` DQL expression instead of a generic `InExpression`.
|
||||
|
||||
As a consequence, `SqlWalker::walkInExpression()` has been replaced by
|
||||
`SqlWalker::walkInListExpression()` and `SqlWalker::walkInSubselectExpression()`.
|
||||
|
||||
## BC BREAK: Changed `EntityManagerInterface#refresh($entity)`, `EntityManagerDecorator#refresh($entity)` and `UnitOfWork#refresh($entity)` signatures
|
||||
|
||||
The new signatures of these methods add an optional `LockMode|int|null $lockMode`
|
||||
param with default `null` value (no lock).
|
||||
|
||||
## BC Break: Removed AnnotationDriver
|
||||
|
||||
The annotation driver and anything related to annotation has been removed.
|
||||
Please migrate to another mapping driver.
|
||||
|
||||
The `Doctrine\ORM\Mapping\Annotation` maker interface has been removed in favor of the new
|
||||
`Doctrine\ORM\Mapping\MappingAttribute` interface.
|
||||
|
||||
## BC BREAK: Removed `EntityManager::create()`
|
||||
|
||||
The constructor of `EntityManager` is now public and must be used instead of the `create()` method.
|
||||
However, the constructor expects a `Connection` while `create()` accepted an array with connection parameters.
|
||||
You can pass that array to DBAL's `Doctrine\DBAL\DriverManager::getConnection()` method to bootstrap the
|
||||
connection.
|
||||
|
||||
## BC BREAK: Removed `QueryBuilder` methods and constants.
|
||||
|
||||
The following `QueryBuilder` constants and methods have been removed:
|
||||
|
||||
1. `SELECT`,
|
||||
2. `DELETE`,
|
||||
3. `UPDATE`,
|
||||
4. `STATE_DIRTY`,
|
||||
5. `STATE_CLEAN`,
|
||||
6. `getState()`,
|
||||
7. `getType()`.
|
||||
|
||||
## BC BREAK: Omitting only the alias argument for `QueryBuilder::update` and `QueryBuilder::delete` is not supported anymore
|
||||
|
||||
When building an UPDATE or DELETE query and when passing a class/type to the function, the alias argument must not be omitted.
|
||||
|
||||
### Before
|
||||
|
||||
```php
|
||||
$qb = $em->createQueryBuilder()
|
||||
->delete('User u')
|
||||
->where('u.id = :user_id')
|
||||
->setParameter('user_id', 1);
|
||||
```
|
||||
|
||||
### After
|
||||
|
||||
```php
|
||||
$qb = $em->createQueryBuilder()
|
||||
->delete('User', 'u')
|
||||
->where('u.id = :user_id')
|
||||
->setParameter('user_id', 1);
|
||||
```
|
||||
|
||||
## BC BREAK: Split output walkers and tree walkers
|
||||
|
||||
`SqlWalker` and its child classes don't implement the `TreeWalker` interface
|
||||
anymore.
|
||||
|
||||
The following methods have been removed from the `TreeWalker` interface and
|
||||
from the `TreeWalkerAdapter` and `TreeWalkerChain` classes:
|
||||
|
||||
* `setQueryComponent()`
|
||||
* `walkSelectClause()`
|
||||
* `walkFromClause()`
|
||||
* `walkFunction()`
|
||||
* `walkOrderByClause()`
|
||||
* `walkOrderByItem()`
|
||||
* `walkHavingClause()`
|
||||
* `walkJoin()`
|
||||
* `walkSelectExpression()`
|
||||
* `walkQuantifiedExpression()`
|
||||
* `walkSubselect()`
|
||||
* `walkSubselectFromClause()`
|
||||
* `walkSimpleSelectClause()`
|
||||
* `walkSimpleSelectExpression()`
|
||||
* `walkAggregateExpression()`
|
||||
* `walkGroupByClause()`
|
||||
* `walkGroupByItem()`
|
||||
* `walkDeleteClause()`
|
||||
* `walkUpdateClause()`
|
||||
* `walkUpdateItem()`
|
||||
* `walkWhereClause()`
|
||||
* `walkConditionalExpression()`
|
||||
* `walkConditionalTerm()`
|
||||
* `walkConditionalFactor()`
|
||||
* `walkConditionalPrimary()`
|
||||
* `walkExistsExpression()`
|
||||
* `walkCollectionMemberExpression()`
|
||||
* `walkEmptyCollectionComparisonExpression()`
|
||||
* `walkNullComparisonExpression()`
|
||||
* `walkInExpression()`
|
||||
* `walkInstanceOfExpression()`
|
||||
* `walkLiteral()`
|
||||
* `walkBetweenExpression()`
|
||||
* `walkLikeExpression()`
|
||||
* `walkStateFieldPathExpression()`
|
||||
* `walkComparisonExpression()`
|
||||
* `walkInputParameter()`
|
||||
* `walkArithmeticExpression()`
|
||||
* `walkArithmeticTerm()`
|
||||
* `walkStringPrimary()`
|
||||
* `walkArithmeticFactor()`
|
||||
* `walkSimpleArithmeticExpression()`
|
||||
* `walkPathExpression()`
|
||||
* `walkResultVariable()`
|
||||
* `getExecutor()`
|
||||
|
||||
The following changes have been made to the abstract `TreeWalkerAdapter` class:
|
||||
|
||||
* The method `setQueryComponent()` is now protected.
|
||||
* The method `_getQueryComponents()` has been removed in favor of
|
||||
`getQueryComponents()`.
|
||||
|
||||
## BC BREAK: Removed identity columns emulation through sequences
|
||||
|
||||
If the platform you are using does not support identity columns, you should
|
||||
switch to the `SEQUENCE` strategy.
|
||||
|
||||
## BC BREAK: Made setters parameters mandatory
|
||||
|
||||
The following methods require an argument when being called. Pass `null`
|
||||
instead of omitting the argument.
|
||||
|
||||
* `Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs::setFoundMetadata()`
|
||||
* `Doctrine\ORM\AbstractQuery::setHydrationCacheProfile()`
|
||||
* `Doctrine\ORM\AbstractQuery::setResultCache()`
|
||||
* `Doctrine\ORM\AbstractQuery::setResultCacheProfile()`
|
||||
|
||||
## BC BREAK: New argument to `NamingStrategy::joinColumnName()`
|
||||
|
||||
### Before
|
||||
|
||||
```php
|
||||
<?php
|
||||
class MyStrategy implements NamingStrategy
|
||||
{
|
||||
/**
|
||||
* @param string $propertyName A property name.
|
||||
*/
|
||||
public function joinColumnName($propertyName): string
|
||||
{
|
||||
// …
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### After
|
||||
|
||||
The `class-string` type for `$className` can be inherited from the signature of
|
||||
the interface.
|
||||
|
||||
```php
|
||||
<?php
|
||||
class MyStrategy implements NamingStrategy
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function joinColumnName(string $propertyName, string $className): string
|
||||
{
|
||||
// …
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## BC BREAK: Remove `StaticPHPDriver` and `DriverChain`
|
||||
|
||||
Use `Doctrine\Persistence\Mapping\Driver\StaticPHPDriver` and
|
||||
`Doctrine\Persistence\Mapping\Driver\MappingDriverChain` from
|
||||
`doctrine/persistence` instead.
|
||||
|
||||
## BC BREAK: `UnderscoreNamingStrategy` is number aware only
|
||||
|
||||
The second argument to `UnderscoreNamingStrategy::__construct()` was dropped,
|
||||
the strategy can no longer be unaware of numbers.
|
||||
|
||||
## BC BREAK: Remove `Doctrine\ORM\Tools\DisconnectedClassMetadataFactory`
|
||||
|
||||
No replacement is provided.
|
||||
|
||||
## BC BREAK: Remove support for `Type::canRequireSQLConversion()`
|
||||
|
||||
This feature was deprecated in DBAL 3.3.0 and will be removed in DBAL 4.0.
|
||||
The value conversion methods are now called regardless of the type.
|
||||
|
||||
The `MappingException::sqlConversionNotAllowedForIdentifiers()` method has been removed
|
||||
as no longer relevant.
|
||||
|
||||
## BC Break: Removed the `doctrine` binary.
|
||||
|
||||
The documentation explains how the console tools can be bootstrapped for
|
||||
standalone usage:
|
||||
|
||||
https://www.doctrine-project.org/projects/doctrine-orm/en/stable/reference/tools.html
|
||||
|
||||
The method `ConsoleRunner::printCliConfigTemplate()` has been removed as well
|
||||
because it was only useful in the context of the `doctrine` binary.
|
||||
|
||||
## BC Break: Removed `EntityManagerHelper` and related logic
|
||||
|
||||
All console commands require a `$entityManagerProvider` to be passed via the
|
||||
constructor. Commands won't try to get the entity manager from a previously
|
||||
registered `em` console helper.
|
||||
|
||||
The following classes have been removed:
|
||||
|
||||
* `Doctrine\ORM\Tools\Console\EntityManagerProvider\HelperSetManagerProvider`
|
||||
* `Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper`
|
||||
|
||||
The following breaking changes have been applied to `Doctrine\ORM\Tools\Console\ConsoleRunner`:
|
||||
|
||||
* The method `createHelperSet()` has been removed.
|
||||
* The methods `run()` and `createApplication()` don't accept an instance of
|
||||
`HelperSet` as first argument anymore.
|
||||
* The method `addCommands()` requires an instance of `EntityManagerProvider`
|
||||
as second argument now.
|
||||
|
||||
## BC Break: `Exception\ORMException` is no longer a class, but an interface
|
||||
|
||||
All methods in `Doctrine\ORM\ORMException` have been extracted to dedicated exceptions.
|
||||
|
||||
* `missingMappingDriverImpl()` => `Exception\MissingMappingDriverImplementation::create()`
|
||||
* `unrecognizedField()` => `Persisters\Exception\UnrecognizedField::byName()`
|
||||
* `unexpectedAssociationValue()` => `Exception\UnexpectedAssociationValue::create()`
|
||||
* `invalidOrientation()` => `Persisters\Exception\InvalidOrientation::fromClassNameAndField()`
|
||||
* `entityManagerClosed()` => `Exception\EntityManagerClosed::create()`
|
||||
* `invalidHydrationMode()` => `Exception\InvalidHydrationMode::fromMode()`
|
||||
* `mismatchedEventManager()` => `Exception\MismatchedEventManager::create()`
|
||||
* `findByRequiresParameter()` => `Repository\Exception\InvalidMagicMethodCall::onMissingParameter()`
|
||||
* `invalidMagicCall()` => `Repository\Exception\InvalidMagicMethodCall::becauseFieldNotFoundIn()`
|
||||
* `invalidFindByInverseAssociation()` => `Repository\Exception\InvalidFindByCall::fromInverseSideUsage()`
|
||||
* `invalidResultCacheDriver()` => `Cache\Exception\InvalidResultCacheDriver::create()`
|
||||
* `notSupported()` => `Exception\NotSupported::create()`
|
||||
* `queryCacheNotConfigured()` => `QueryCacheNotConfigured::create()`
|
||||
* `metadataCacheNotConfigured()` => `Cache\Exception\MetadataCacheNotConfigured::create()`
|
||||
* `queryCacheUsesNonPersistentCache()` => `Cache\Exception\QueryCacheUsesNonPersistentCache::fromDriver()`
|
||||
* `metadataCacheUsesNonPersistentCache()` => `Cache\Exception\MetadataCacheUsesNonPersistentCache::fromDriver()`
|
||||
* `proxyClassesAlwaysRegenerating()` => `Exception\ProxyClassesAlwaysRegenerating::create()`
|
||||
* `invalidEntityRepository()` => `Exception\InvalidEntityRepository::fromClassName()`
|
||||
* `missingIdentifierField()` => `Exception\MissingIdentifierField::fromFieldAndClass()`
|
||||
* `unrecognizedIdentifierFields()` => `Exception\UnrecognizedIdentifierFields::fromClassAndFieldNames()`
|
||||
* `cantUseInOperatorOnCompositeKeys()` => `Persisters\Exception\CantUseInOperatorOnCompositeKeys::create()`
|
||||
|
||||
## BC Break: `CacheException` is no longer a class, but an interface
|
||||
|
||||
All methods in `Doctrine\ORM\Cache\CacheException` have been extracted to dedicated exceptions.
|
||||
|
||||
* `updateReadOnlyCollection()` => `Cache\Exception\CannotUpdateReadOnlyCollection::fromEntityAndField()`
|
||||
* `updateReadOnlyEntity()` => `Cache\Exception\CannotUpdateReadOnlyEntity::fromEntity()`
|
||||
* `nonCacheableEntity()` => `Cache\Exception\NonCacheableEntity::fromEntity()`
|
||||
* `nonCacheableEntityAssociation()` => `Cache\Exception\NonCacheableEntityAssociation::fromEntityAndField()`
|
||||
|
||||
|
||||
## BC Break: Missing type declaration added for identifier generators
|
||||
|
||||
Although undocumented, it was possible to configure a custom repository
|
||||
class that implements `ObjectRepository` but does not extend the
|
||||
`EntityRepository` base class. Repository classes have to extend
|
||||
`EntityRepository` now.
|
||||
|
||||
## BC BREAK: Removed support for entity namespace alias
|
||||
|
||||
- `EntityManager::getRepository()` no longer accepts the entity namespace alias
|
||||
notation.
|
||||
- `Configuration::addEntityNamespace()` and
|
||||
`Configuration::getEntityNamespace()` have been removed.
|
||||
|
||||
## BC BREAK: Remove helper methods from `AbstractCollectionPersister`
|
||||
|
||||
The following protected methods of
|
||||
`Doctrine\ORM\Cache\Persister\Collection\AbstractCollectionPersister`
|
||||
have been removed.
|
||||
|
||||
* `evictCollectionCache()`
|
||||
* `evictElementCache()`
|
||||
|
||||
## BC BREAK: `Doctrine\ORM\Query\TreeWalkerChainIterator`
|
||||
|
||||
This class has been removed without replacement.
|
||||
|
||||
## BC BREAK: Remove quoting methods from `ClassMetadata`
|
||||
|
||||
The following methods have been removed from the class metadata because
|
||||
quoting is handled by implementations of `Doctrine\ORM\Mapping\QuoteStrategy`:
|
||||
|
||||
* `getQuotedIdentifierColumnNames()`
|
||||
* `getQuotedColumnName()`
|
||||
* `getQuotedTableName()`
|
||||
* `getQuotedJoinTableName()`
|
||||
|
||||
## BC BREAK: Remove ability to merge detached entities
|
||||
|
||||
Merge semantics was a poor fit for the PHP "share-nothing" architecture.
|
||||
In addition to that, merging caused multiple issues with data integrity
|
||||
in the managed entity graph, which was constantly spawning more edge-case
|
||||
bugs/scenarios.
|
||||
|
||||
The method `UnitOfWork::merge()` has been removed. The method
|
||||
`EntityManager::merge()` will throw an exception on each call.
|
||||
|
||||
## BC BREAK: Removed ability to partially flush/commit entity manager and unit of work
|
||||
|
||||
The following methods don't accept a single entity or an array of entities anymore:
|
||||
|
||||
* `Doctrine\ORM\EntityManager::flush()`
|
||||
* `Doctrine\ORM\Decorator\EntityManagerDecorator::flush()`
|
||||
* `Doctrine\ORM\UnitOfWork::commit()`
|
||||
|
||||
The semantics of `flush()` and `commit()` will remain the same, but the change
|
||||
tracking will be performed on all entities managed by the unit of work, and not
|
||||
just on the provided entities, as the parameter is now completely ignored.
|
||||
|
||||
## BC BREAK: Removed ability to partially clear entity manager and unit of work
|
||||
|
||||
* Passing an argument other than `null` to `EntityManager::clear()` will raise
|
||||
an exception.
|
||||
* The unit of work cannot be cleared partially anymore. Passing an argument to
|
||||
`UnitOfWork::clear()` does not have any effect anymore; the unit of work is
|
||||
cleared completely.
|
||||
* The method `EntityRepository::clear()` has been removed.
|
||||
* The methods `getEntityClass()` and `clearsAllEntities()` have been removed
|
||||
from `OnClearEventArgs`.
|
||||
|
||||
## BC BREAK: Remove support for Doctrine Cache
|
||||
|
||||
The Doctrine Cache library is not supported anymore. The following methods
|
||||
have been removed from `Doctrine\ORM\Configuration`:
|
||||
|
||||
* `getQueryCacheImpl()`
|
||||
* `setQueryCacheImpl()`
|
||||
* `getHydrationCacheImpl()`
|
||||
* `setHydrationCacheImpl()`
|
||||
* `getMetadataCacheImpl()`
|
||||
* `setMetadataCacheImpl()`
|
||||
|
||||
The methods have been replaced by PSR-6 compatible counterparts
|
||||
(just strip the `Impl` suffix from the old name to get the new one).
|
||||
|
||||
## BC BREAK: Remove `Doctrine\ORM\Configuration::newDefaultAnnotationDriver`
|
||||
|
||||
This functionality has been moved to the new `ORMSetup` class. Call
|
||||
`Doctrine\ORM\ORMSetup::createDefaultAnnotationDriver()` to create
|
||||
a new annotation driver.
|
||||
|
||||
## BC BREAK: Remove `Doctrine\ORM\Tools\Setup`
|
||||
|
||||
In our effort to migrate from Doctrine Cache to PSR-6, the `Setup` class which
|
||||
accepted a Doctrine Cache instance in each method has been removed.
|
||||
|
||||
The replacement is `Doctrine\ORM\ORMSetup` which accepts a PSR-6
|
||||
cache instead.
|
||||
|
||||
## BC BREAK: Removed named queries
|
||||
|
||||
All APIs related to named queries have been removed.
|
||||
|
||||
## BC BREAK: Remove old cache accessors and mutators from query classes
|
||||
|
||||
The following methods have been removed from `AbstractQuery`:
|
||||
|
||||
* `setResultCacheDriver()`
|
||||
* `getResultCacheDriver()`
|
||||
* `useResultCache()`
|
||||
* `getResultCacheLifetime()`
|
||||
* `getResultCacheId()`
|
||||
|
||||
The following methods have been removed from `Query`:
|
||||
|
||||
* `setQueryCacheDriver()`
|
||||
* `getQueryCacheDriver()`
|
||||
|
||||
## BC BREAK: Remove `Doctrine\ORM\Cache\MultiGetRegion`
|
||||
|
||||
The interface has been merged into `Doctrine\ORM\Cache\Region`.
|
||||
|
||||
## BC BREAK: Rename `AbstractIdGenerator::generate()` to `generateId()`
|
||||
|
||||
* Implementations of `AbstractIdGenerator` have to implement the method
|
||||
`generateId()`.
|
||||
* The method `generate()` has been removed from `AbstractIdGenerator`.
|
||||
|
||||
## BC BREAK: Remove cache settings inspection
|
||||
|
||||
Doctrine does not provide its own cache implementation anymore and relies on
|
||||
the PSR-6 standard instead. As a consequence, we cannot determine anymore
|
||||
whether a given cache adapter is suitable for a production environment.
|
||||
Because of that, functionality that aims to do so has been removed:
|
||||
|
||||
* `Configuration::ensureProductionSettings()`
|
||||
* the `orm:ensure-production-settings` console command
|
||||
|
||||
## BC BREAK: PSR-6-based second level cache
|
||||
|
||||
The second level cache has been reworked to consume a PSR-6 cache. Using a
|
||||
Doctrine Cache instance is not supported anymore.
|
||||
|
||||
* `DefaultCacheFactory`: The constructor expects a PSR-6 cache item pool as
|
||||
second argument now.
|
||||
* `DefaultMultiGetRegion`: This class has been removed.
|
||||
* `DefaultRegion`:
|
||||
* The constructor expects a PSR-6 cache item pool as second argument now.
|
||||
* The protected `$cache` property is removed.
|
||||
* The properties `$name` and `$lifetime` as well as the constant
|
||||
`REGION_KEY_SEPARATOR` and the method `getCacheEntryKey()` are
|
||||
`private` now.
|
||||
* The method `getCache()` has been removed.
|
||||
|
||||
|
||||
## BC Break: Remove `Doctrine\ORM\Mapping\Driver\PHPDriver`
|
||||
|
||||
Use `StaticPHPDriver` instead when you want to programmatically configure
|
||||
entity metadata.
|
||||
|
||||
## BC BREAK: Remove `Doctrine\ORM\EntityManagerInterface#transactional()`
|
||||
|
||||
This method has been replaced by `Doctrine\ORM\EntityManagerInterface#wrapInTransaction()`.
|
||||
|
||||
## BC BREAK: Removed support for schema emulation.
|
||||
|
||||
The ORM no longer attempts to emulate schemas on SQLite.
|
||||
|
||||
## BC BREAK: Remove `Setup::registerAutoloadDirectory()`
|
||||
|
||||
Use Composer's autoloader instead.
|
||||
|
||||
## BC BREAK: Remove YAML mapping drivers.
|
||||
|
||||
If your code relies on `YamlDriver` or `SimpleYamlDriver`, you **MUST** migrate to
|
||||
attribute, annotation or XML drivers instead.
|
||||
|
||||
You can use the `orm:convert-mapping` command to convert your metadata mapping to XML
|
||||
_before_ upgrading to 3.0:
|
||||
|
||||
```sh
|
||||
php doctrine orm:convert-mapping xml /path/to/mapping-path-converted-to-xml
|
||||
```
|
||||
|
||||
## BC BREAK: Remove code generators and related console commands
|
||||
|
||||
These console commands have been removed:
|
||||
|
||||
* `orm:convert-d1-schema`
|
||||
* `orm:convert-mapping`
|
||||
* `orm:generate:entities`
|
||||
* `orm:generate-repositories`
|
||||
|
||||
These classes have been deprecated:
|
||||
|
||||
* `Doctrine\ORM\Tools\ConvertDoctrine1Schema`
|
||||
* `Doctrine\ORM\Tools\EntityGenerator`
|
||||
* `Doctrine\ORM\Tools\EntityRepositoryGenerator`
|
||||
|
||||
The entire `Doctrine\ORM\Tools\Export` namespace has been removed as well.
|
||||
|
||||
## BC BREAK: Removed `Doctrine\ORM\Version`
|
||||
|
||||
Use Composer's runtime API if you _really_ need to check the version of the ORM package at runtime.
|
||||
|
||||
## BC BREAK: EntityRepository::count() signature change
|
||||
|
||||
The argument `$criteria` of `Doctrine\ORM\EntityRepository::count()` is now
|
||||
optional. Overrides in child classes should be made compatible.
|
||||
|
||||
## BC BREAK: changes in exception hierarchy
|
||||
|
||||
- `Doctrine\ORM\ORMException` has been removed
|
||||
- `Doctrine\ORM\Exception\ORMException` is now an interface
|
||||
|
||||
## Variadic methods now use native variadics
|
||||
The following methods were using `func_get_args()` to simulate a variadic argument:
|
||||
- `Doctrine\ORM\Query\Expr#andX()`
|
||||
- `Doctrine\ORM\Query\Expr#orX()`
|
||||
- `Doctrine\ORM\QueryBuilder#select()`
|
||||
- `Doctrine\ORM\QueryBuilder#addSelect()`
|
||||
- `Doctrine\ORM\QueryBuilder#where()`
|
||||
- `Doctrine\ORM\QueryBuilder#andWhere()`
|
||||
- `Doctrine\ORM\QueryBuilder#orWhere()`
|
||||
- `Doctrine\ORM\QueryBuilder#groupBy()`
|
||||
- `Doctrine\ORM\QueryBuilder#andGroupBy()`
|
||||
- `Doctrine\ORM\QueryBuilder#having()`
|
||||
- `Doctrine\ORM\QueryBuilder#andHaving()`
|
||||
- `Doctrine\ORM\QueryBuilder#orHaving()`
|
||||
A variadic argument is now actually used in their signatures signature (`...$x`).
|
||||
Signatures of overridden methods should be changed accordingly
|
||||
|
||||
## Minor BC BREAK: removed `Doctrine\ORM\EntityManagerInterface#copy()`
|
||||
|
||||
Method `Doctrine\ORM\EntityManagerInterface#copy()` never got its implementation and is removed in 3.0.
|
||||
|
||||
## BC BREAK: Removed classes related to UUID and TABLE generator strategies
|
||||
|
||||
The following classes have been removed:
|
||||
- `Doctrine\ORM\Id\TableGenerator`
|
||||
- `Doctrine\ORM\Id\UuidGenerator`
|
||||
|
||||
Using the `UUID` strategy for generating identifiers is not supported anymore.
|
||||
|
||||
## BC BREAK: Removed `Query::iterate()`
|
||||
|
||||
The deprecated method `Query::iterate()` has been removed along with the
|
||||
following classes and methods:
|
||||
|
||||
- `AbstractHydrator::iterate()`
|
||||
- `AbstractHydrator::hydrateRow()`
|
||||
- `IterableResult`
|
||||
|
||||
Use `toIterable()` instead.
|
||||
|
||||
# Upgrade to 2.20
|
||||
|
||||
## Add `Doctrine\ORM\Query\OutputWalker` interface, deprecate `Doctrine\ORM\Query\SqlWalker::getExecutor()`
|
||||
|
||||
Output walkers should implement the new `\Doctrine\ORM\Query\OutputWalker` interface and create
|
||||
`Doctrine\ORM\Query\Exec\SqlFinalizer` instances instead of `Doctrine\ORM\Query\Exec\AbstractSqlExecutor`s.
|
||||
The output walker must not base its workings on the query `firstResult`/`maxResult` values, so that the
|
||||
`SqlFinalizer` can be kept in the query cache and used regardless of the actual `firstResult`/`maxResult` values.
|
||||
Any operation dependent on `firstResult`/`maxResult` should take place within the `SqlFinalizer::createExecutor()`
|
||||
method. Details can be found at https://github.com/doctrine/orm/pull/11188.
|
||||
|
||||
## Explictly forbid property hooks
|
||||
|
||||
Property hooks are not supported yet by Doctrine ORM. Until support is added,
|
||||
they are explicitly forbidden because the support would result in a breaking
|
||||
change in behavior.
|
||||
|
||||
Progress on this is tracked at https://github.com/doctrine/orm/issues/11624 .
|
||||
|
||||
## PARTIAL DQL syntax is undeprecated
|
||||
|
||||
Use of the PARTIAL keyword is not deprecated anymore in DQL, because we will be
|
||||
able to support PARTIAL objects with PHP 8.4 Lazy Objects and
|
||||
Symfony/VarExporter in a better way. When we decided to remove this feature
|
||||
these two abstractions did not exist yet.
|
||||
|
||||
WARNING: If you want to upgrade to 3.x and still use PARTIAL keyword in DQL
|
||||
with array or object hydrators, then you have to directly migrate to ORM 3.3.x or higher.
|
||||
PARTIAL keyword in DQL is not available in 3.0, 3.1 and 3.2 of ORM.
|
||||
|
||||
## Deprecate `\Doctrine\ORM\Query\Parser::setCustomOutputTreeWalker()`
|
||||
|
||||
Use the `\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER` query hint to set the output walker
|
||||
class instead of setting it through the `\Doctrine\ORM\Query\Parser::setCustomOutputTreeWalker()` method
|
||||
on the parser instance.
|
||||
|
||||
# Upgrade to 2.19
|
||||
|
||||
## Deprecate calling `ClassMetadata::getAssociationMappedByTargetField()` with the owning side of an association
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
include(__DIR__ . '/doctrine.php');
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
fwrite(
|
||||
STDERR,
|
||||
'[Warning] The use of this script is discouraged. See'
|
||||
. ' https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/tools.html#doctrine-console'
|
||||
. ' for instructions on bootstrapping the console runner.'
|
||||
. PHP_EOL
|
||||
);
|
||||
|
||||
echo PHP_EOL . PHP_EOL;
|
||||
|
||||
require_once 'Doctrine/Common/ClassLoader.php';
|
||||
|
||||
$classLoader = new \Doctrine\Common\ClassLoader('Doctrine');
|
||||
$classLoader->register();
|
||||
|
||||
$classLoader = new \Doctrine\Common\ClassLoader('Symfony');
|
||||
$classLoader->register();
|
||||
|
||||
$configFile = getcwd() . DIRECTORY_SEPARATOR . 'cli-config.php';
|
||||
|
||||
$helperSet = null;
|
||||
if (file_exists($configFile)) {
|
||||
if ( ! is_readable($configFile)) {
|
||||
trigger_error(
|
||||
'Configuration file [' . $configFile . '] does not have read permission.', E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
require $configFile;
|
||||
|
||||
foreach ($GLOBALS as $helperSetCandidate) {
|
||||
if ($helperSetCandidate instanceof \Symfony\Component\Console\Helper\HelperSet) {
|
||||
$helperSet = $helperSetCandidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$helperSet = ($helperSet) ?: new \Symfony\Component\Console\Helper\HelperSet();
|
||||
|
||||
\Doctrine\ORM\Tools\Console\ConsoleRunner::run($helperSet);
|
||||
@@ -1,9 +0,0 @@
|
||||
@echo off
|
||||
|
||||
if "%PHPBIN%" == "" set PHPBIN=@php_bin@
|
||||
if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
|
||||
GOTO RUN
|
||||
:USE_PEAR_PATH
|
||||
set PHPBIN=%PHP_PEAR_PHP_BIN%
|
||||
:RUN
|
||||
"%PHPBIN%" "@bin_dir@\doctrine" %*
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
||||
|
||||
fwrite(
|
||||
STDERR,
|
||||
'[Warning] The use of this script is discouraged. See'
|
||||
. ' https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/tools.html#doctrine-console'
|
||||
. ' for instructions on bootstrapping the console runner.'
|
||||
. PHP_EOL
|
||||
);
|
||||
|
||||
echo PHP_EOL . PHP_EOL;
|
||||
|
||||
$autoloadFiles = [
|
||||
__DIR__ . '/../vendor/autoload.php',
|
||||
__DIR__ . '/../../../autoload.php'
|
||||
];
|
||||
|
||||
foreach ($autoloadFiles as $autoloadFile) {
|
||||
if (file_exists($autoloadFile)) {
|
||||
require_once $autoloadFile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$directories = [getcwd(), getcwd() . DIRECTORY_SEPARATOR . 'config'];
|
||||
|
||||
$configFile = null;
|
||||
foreach ($directories as $directory) {
|
||||
$configFile = $directory . DIRECTORY_SEPARATOR . 'cli-config.php';
|
||||
|
||||
if (file_exists($configFile)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! file_exists($configFile)) {
|
||||
ConsoleRunner::printCliConfigTemplate();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( ! is_readable($configFile)) {
|
||||
echo 'Configuration file [' . $configFile . '] does not have read permission.' . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$commands = [];
|
||||
|
||||
$helperSet = require $configFile;
|
||||
|
||||
if ( ! ($helperSet instanceof HelperSet)) {
|
||||
foreach ($GLOBALS as $helperSetCandidate) {
|
||||
if ($helperSetCandidate instanceof HelperSet) {
|
||||
$helperSet = $helperSetCandidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleRunner::run($helperSet, $commands);
|
||||
@@ -3,9 +3,13 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
@@ -14,9 +18,13 @@
|
||||
<var name="db_port" value="3306"/>
|
||||
<var name="db_user" value="root" />
|
||||
<var name="db_dbname" value="doctrine_tests" />
|
||||
<var name="db_default_table_option_charset" value="utf8mb4" />
|
||||
<var name="db_default_table_option_collation" value="utf8mb4_unicode_ci" />
|
||||
<var name="db_default_table_option_engine" value="InnoDB" />
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -25,11 +33,11 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</include>
|
||||
</source>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
@@ -14,9 +18,13 @@
|
||||
<var name="db_port" value="3306"/>
|
||||
<var name="db_user" value="root" />
|
||||
<var name="db_dbname" value="doctrine_tests" />
|
||||
<var name="db_default_table_option_charset" value="utf8mb4" />
|
||||
<var name="db_default_table_option_collation" value="utf8mb4_unicode_ci" />
|
||||
<var name="db_default_table_option_engine" value="InnoDB" />
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -25,12 +33,11 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
</include>
|
||||
</source>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
@@ -17,6 +21,7 @@
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -25,11 +30,11 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</include>
|
||||
</source>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
@@ -15,6 +19,7 @@
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -23,11 +28,11 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</include>
|
||||
</source>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
@@ -17,6 +21,7 @@
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -25,11 +30,11 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</include>
|
||||
</source>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
displayDetailsOnTestsThatTriggerDeprecations="true"
|
||||
displayDetailsOnTestsThatTriggerNotices="true"
|
||||
displayDetailsOnTestsThatTriggerWarnings="true"
|
||||
failOnNotice="true"
|
||||
failOnWarning="true"
|
||||
failOnRisky="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
@@ -15,6 +19,7 @@
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
@@ -23,11 +28,11 @@
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<source ignoreSuppressionOfDeprecations="true">
|
||||
<include>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</include>
|
||||
</source>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
|
||||
@@ -15,49 +15,42 @@
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0",
|
||||
"php": "^8.1",
|
||||
"composer-runtime-api": "^2",
|
||||
"ext-ctype": "*",
|
||||
"doctrine/cache": "^1.12.1 || ^2.1.1",
|
||||
"doctrine/collections": "^1.5 || ^2.1",
|
||||
"doctrine/common": "^3.0.3",
|
||||
"doctrine/dbal": "^2.13.1 || ^3.2",
|
||||
"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": "^2 || ^3",
|
||||
"doctrine/persistence": "^2.4 || ^3",
|
||||
"doctrine/lexer": "^3",
|
||||
"doctrine/persistence": "^3.3.1 || ^4",
|
||||
"psr/cache": "^1 || ^2 || ^3",
|
||||
"symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/polyfill-php72": "^1.23",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
"symfony/console": "^5.4 || ^6.0 || ^7.0",
|
||||
"symfony/var-exporter": "^6.3.9 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "^1.13 || ^2",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^12.0",
|
||||
"phpbench/phpbench": "^0.16.10 || ^1.0",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.11.1",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
|
||||
"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.7.2",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0",
|
||||
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0",
|
||||
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0",
|
||||
"vimeo/psalm": "4.30.0 || 5.24.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/annotations": "<1.13 || >= 3.0"
|
||||
"squizlabs/php_codesniffer": "3.12.0",
|
||||
"symfony/cache": "^5.4 || ^6.2 || ^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Provides support for XSD validation for XML mapping files",
|
||||
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0",
|
||||
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
|
||||
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Doctrine\\ORM\\": "src" }
|
||||
@@ -69,7 +62,6 @@
|
||||
"Doctrine\\Performance\\": "tests/Performance"
|
||||
}
|
||||
},
|
||||
"bin": ["bin/doctrine"],
|
||||
"archive": {
|
||||
"exclude": ["!vendor", "tests", "*phpunit.xml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp"]
|
||||
}
|
||||
|
||||
3
docs/.gitignore
vendored
Normal file
3
docs/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
composer.lock
|
||||
vendor/
|
||||
build/
|
||||
24
docs/Makefile
Normal file
24
docs/Makefile
Normal file
@@ -0,0 +1,24 @@
|
||||
# Makefile for Doctrine ORM documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
DOCOPTS =
|
||||
BUILD = vendor/bin/guides
|
||||
BUILDDIR = build
|
||||
|
||||
# Internal variables.
|
||||
ALLGUIDESOPTS = $(DOCOPTS) en/
|
||||
|
||||
.PHONY: help clean html
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
|
||||
clean:
|
||||
-rm -rf ./$(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(BUILD) $(ALLGUIDESOPTS) --output=$(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
@@ -1,18 +1,22 @@
|
||||
# Doctrine ORM Documentation
|
||||
|
||||
The documentation is written in [ReStructured Text](https://docutils.sourceforge.io/rst.html).
|
||||
|
||||
## How to Generate:
|
||||
Using Ubuntu 14.04 LTS:
|
||||
|
||||
1. Run ./bin/install-dependencies.sh
|
||||
2. Run ./bin/generate-docs.sh
|
||||
In the `docs/` folder, run
|
||||
|
||||
It will generate the documentation into the build directory of the checkout.
|
||||
composer update
|
||||
|
||||
Then compile the documentation with:
|
||||
|
||||
## Theme issues
|
||||
make html
|
||||
|
||||
If you get a "Theme error", check if the `en/_theme` subdirectory is empty,
|
||||
in which case you will need to run:
|
||||
This will generate the documentation into the `build` subdirectory.
|
||||
|
||||
1. git submodule init
|
||||
2. git submodule update
|
||||
To browse the documentation, you need to run a webserver:
|
||||
|
||||
cd build/html
|
||||
php -S localhost:8000
|
||||
|
||||
Now the documentation is available at [http://localhost:8000](http://localhost:8000).
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
EXECPATH=`dirname $0`
|
||||
cd $EXECPATH
|
||||
cd ..
|
||||
|
||||
rm build -Rf
|
||||
sphinx-build en build
|
||||
|
||||
sphinx-build -b latex en build/pdf
|
||||
rubber --into build/pdf --pdf build/pdf/Doctrine2ORM.tex
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/bash
|
||||
sudo apt-get update && sudo apt-get install -y python2.7 python-sphinx python-pygments
|
||||
10
docs/composer.json
Normal file
10
docs/composer.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "doctrine/orm-docs",
|
||||
"description": "Documentation for the Object-Relational Mapper\"",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"phpdocumentor/guides-cli": "1.7.1",
|
||||
"phpdocumentor/filesystem": "1.7.1"
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Doctrine2ORM.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Doctrine2ORM.qhc"
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
|
||||
"run these through (pdf)latex."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
@@ -1,93 +0,0 @@
|
||||
#Copyright (c) 2010 Fabien Potencier
|
||||
#
|
||||
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
#of this software and associated documentation files (the "Software"), to deal
|
||||
#in the Software without restriction, including without limitation the rights
|
||||
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
#copies of the Software, and to permit persons to whom the Software is furnished
|
||||
#to do so, subject to the following conditions:
|
||||
#
|
||||
#The above copyright notice and this permission notice shall be included in all
|
||||
#copies or substantial portions of the Software.
|
||||
#
|
||||
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
#THE SOFTWARE.
|
||||
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
from docutils import nodes
|
||||
from string import upper
|
||||
|
||||
class configurationblock(nodes.General, nodes.Element):
|
||||
pass
|
||||
|
||||
class ConfigurationBlock(Directive):
|
||||
has_content = True
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {}
|
||||
formats = {
|
||||
'html': 'HTML',
|
||||
'xml': 'XML',
|
||||
'php': 'PHP',
|
||||
'yaml': 'YAML',
|
||||
'jinja': 'Twig',
|
||||
'html+jinja': 'Twig',
|
||||
'jinja+html': 'Twig',
|
||||
'php+html': 'PHP',
|
||||
'html+php': 'PHP',
|
||||
'ini': 'INI',
|
||||
'php-annotations': 'Annotations',
|
||||
}
|
||||
|
||||
def run(self):
|
||||
env = self.state.document.settings.env
|
||||
|
||||
node = nodes.Element()
|
||||
node.document = self.state.document
|
||||
self.state.nested_parse(self.content, self.content_offset, node)
|
||||
|
||||
entries = []
|
||||
for i, child in enumerate(node):
|
||||
if isinstance(child, nodes.literal_block):
|
||||
# add a title (the language name) before each block
|
||||
#targetid = "configuration-block-%d" % env.new_serialno('configuration-block')
|
||||
#targetnode = nodes.target('', '', ids=[targetid])
|
||||
#targetnode.append(child)
|
||||
|
||||
innernode = nodes.emphasis(self.formats[child['language']], self.formats[child['language']])
|
||||
|
||||
para = nodes.paragraph()
|
||||
para += [innernode, child]
|
||||
|
||||
entry = nodes.list_item('')
|
||||
entry.append(para)
|
||||
entries.append(entry)
|
||||
|
||||
resultnode = configurationblock()
|
||||
resultnode.append(nodes.bullet_list('', *entries))
|
||||
|
||||
return [resultnode]
|
||||
|
||||
def visit_configurationblock_html(self, node):
|
||||
self.body.append(self.starttag(node, 'div', CLASS='configuration-block'))
|
||||
|
||||
def depart_configurationblock_html(self, node):
|
||||
self.body.append('</div>\n')
|
||||
|
||||
def visit_configurationblock_latex(self, node):
|
||||
pass
|
||||
|
||||
def depart_configurationblock_latex(self, node):
|
||||
pass
|
||||
|
||||
def setup(app):
|
||||
app.add_node(configurationblock,
|
||||
html=(visit_configurationblock_html, depart_configurationblock_html),
|
||||
latex=(visit_configurationblock_latex, depart_configurationblock_latex))
|
||||
app.add_directive('configuration-block', ConfigurationBlock)
|
||||
Submodule docs/en/_theme deleted from 6f1bc8bead
@@ -140,11 +140,6 @@ Now we're going to create the ``point`` type and implement all required methods.
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function canRequireSQLConversion()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function convertToPHPValueSQL($sqlExpr, AbstractPlatform $platform)
|
||||
{
|
||||
return sprintf('AsText(%s)', $sqlExpr);
|
||||
|
||||
@@ -352,7 +352,7 @@ the database using a FOR UPDATE.
|
||||
use Bank\Entities\Account;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
|
||||
$account = $em->find(Account::class, $accId, LockMode::PESSIMISTIC_READ);
|
||||
$account = $em->find(Account::class, $accId, LockMode::PESSIMISTIC_WRITE);
|
||||
|
||||
Keeping Updates and Deletes in Sync
|
||||
-----------------------------------
|
||||
|
||||
@@ -232,6 +232,33 @@ vendors SQL parser to show us further errors in the parsing
|
||||
process, for example if the Unit would not be one of the supported
|
||||
values by MySql.
|
||||
|
||||
Typed functions
|
||||
---------------
|
||||
By default, result of custom functions is fetched as-is from the database driver.
|
||||
If you want to be sure that the type is always the same, then your custom function needs to
|
||||
implement ``Doctrine\ORM\Query\AST\TypedExpression``. Then, the result is wired
|
||||
through ``Doctrine\DBAL\Types\Type::convertToPhpValue()`` of the ``Type`` returned in ``getReturnType()``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\AST\TypedExpression;
|
||||
|
||||
class DateDiff extends FunctionNode implements TypedExpression
|
||||
{
|
||||
// ...
|
||||
|
||||
public function getReturnType(): Type
|
||||
{
|
||||
return Type::getType(Types::INTEGER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Conclusion
|
||||
----------
|
||||
|
||||
|
||||
44
docs/en/cookbook/generated-columns.rst
Normal file
44
docs/en/cookbook/generated-columns.rst
Normal file
@@ -0,0 +1,44 @@
|
||||
Generated Columns
|
||||
=================
|
||||
|
||||
Generated columns, sometimes also called virtual columns, are populated by
|
||||
the database engine itself. They are a tool for performance optimization, to
|
||||
avoid calculating a value on each query.
|
||||
|
||||
You can define generated columns on entities and have Doctrine map the values
|
||||
to your entity.
|
||||
|
||||
Declaring a generated column
|
||||
----------------------------
|
||||
|
||||
There is no explicit mapping instruction for generated columns. Instead, you
|
||||
specify that the column should not be written to, and define a custom column
|
||||
definition.
|
||||
|
||||
.. literalinclude:: generated-columns/Person.php
|
||||
:language: php
|
||||
|
||||
* ``insertable``, ``updatable``: Setting these to false tells Doctrine to never
|
||||
write this column - writing to a generated column would result in an error
|
||||
from the database.
|
||||
* ``columnDefinition``: We specify the full DDL to create the column. To allow
|
||||
to use database specific features, this attribute does not use Doctrine Query
|
||||
Language but native SQL. Note that you need to reference columns by their
|
||||
database name (either explicitly set in the mapping or per the current
|
||||
:doc:`naming strategy <../reference/namingstrategy>`).
|
||||
Be aware that specifying a column definition makes the ``SchemaTool``
|
||||
completely ignore all other configuration for this column. See also
|
||||
:ref:`#[Column] <attrref_column>`
|
||||
* ``generated``: Specifying that this column is always generated tells Doctrine
|
||||
to update the field on the entity with the value from the database after
|
||||
every write operation.
|
||||
|
||||
Advanced example: Extracting a value from a JSON structure
|
||||
----------------------------------------------------------
|
||||
|
||||
Lets assume we have an entity that stores a blogpost as structured JSON.
|
||||
To avoid extracting all titles on the fly when listing the posts, we create a
|
||||
generated column with the field.
|
||||
|
||||
.. literalinclude:: generated-columns/Article.php
|
||||
:language: php
|
||||
33
docs/en/cookbook/generated-columns/Article.php
Normal file
33
docs/en/cookbook/generated-columns/Article.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity]
|
||||
class Article
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private int $id;
|
||||
|
||||
/**
|
||||
* When working with Postgres, it is recommended to use the jsonb
|
||||
* format for better performance.
|
||||
*/
|
||||
#[ORM\Column(options: ['jsonb' => true])]
|
||||
private array $content;
|
||||
|
||||
/**
|
||||
* Because we specify NOT NULL, inserting will fail if the content does
|
||||
* not have a string in the title field.
|
||||
*/
|
||||
#[ORM\Column(
|
||||
insertable: false,
|
||||
updatable: false,
|
||||
columnDefinition: "VARCHAR(255) generated always as (content->>'title') stored NOT NULL",
|
||||
generated: 'ALWAYS',
|
||||
)]
|
||||
private string $title;
|
||||
}
|
||||
24
docs/en/cookbook/generated-columns/Person.php
Normal file
24
docs/en/cookbook/generated-columns/Person.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity]
|
||||
class Person
|
||||
{
|
||||
#[ORM\Column(type: 'string')]
|
||||
private string $firstName;
|
||||
|
||||
#[ORM\Column(type: 'string', name: 'name')]
|
||||
private string $lastName;
|
||||
|
||||
#[ORM\Column(
|
||||
type: 'string',
|
||||
insertable: false,
|
||||
updatable: false,
|
||||
columnDefinition: "VARCHAR(255) GENERATED ALWAYS AS (concat(firstName, ' ', name) stored NOT NULL",
|
||||
generated: 'ALWAYS',
|
||||
)]
|
||||
private string $fullName;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
Implementing the Notify ChangeTracking Policy
|
||||
=============================================
|
||||
|
||||
.. sectionauthor:: Roman Borschel <roman@code-factory.org>
|
||||
|
||||
The NOTIFY change-tracking policy is the most effective
|
||||
change-tracking policy provided by Doctrine but it requires some
|
||||
boilerplate code. This recipe will show you how this boilerplate
|
||||
code should look like. We will implement it on a
|
||||
`Layer Supertype <https://martinfowler.com/eaaCatalog/layerSupertype.html>`_
|
||||
for all our domain objects.
|
||||
|
||||
.. note::
|
||||
|
||||
The notify change tracking policy is deprecated and will be removed in ORM 3.0.
|
||||
(\ `Details <https://github.com/doctrine/orm/issues/8383>`_)
|
||||
|
||||
Implementing NotifyPropertyChanged
|
||||
----------------------------------
|
||||
|
||||
The NOTIFY policy is based on the assumption that the entities
|
||||
notify interested listeners of changes to their properties. For
|
||||
that purpose, a class that wants to use this policy needs to
|
||||
implement the ``NotifyPropertyChanged`` interface from the
|
||||
``Doctrine\Common`` namespace.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\Persistence\NotifyPropertyChanged;
|
||||
use Doctrine\Persistence\PropertyChangedListener;
|
||||
|
||||
abstract class DomainObject implements NotifyPropertyChanged
|
||||
{
|
||||
private $listeners = array();
|
||||
|
||||
public function addPropertyChangedListener(PropertyChangedListener $listener) {
|
||||
$this->listeners[] = $listener;
|
||||
}
|
||||
|
||||
/** Notifies listeners of a change. */
|
||||
protected function onPropertyChanged($propName, $oldValue, $newValue) {
|
||||
if ($this->listeners) {
|
||||
foreach ($this->listeners as $listener) {
|
||||
$listener->propertyChanged($this, $propName, $oldValue, $newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Then, in each property setter of concrete, derived domain classes,
|
||||
you need to invoke onPropertyChanged as follows to notify
|
||||
listeners:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// Mapping not shown, either in attributes, annotations, xml or yaml as usual
|
||||
class MyEntity extends DomainObject
|
||||
{
|
||||
private $data;
|
||||
// ... other fields as usual
|
||||
|
||||
public function setData($data) {
|
||||
if ($data != $this->data) { // check: is it actually modified?
|
||||
$this->onPropertyChanged('data', $this->data, $data);
|
||||
$this->data = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
The check whether the new value is different from the old one is
|
||||
not mandatory but recommended. That way you can avoid unnecessary
|
||||
updates and also have full control over when you consider a
|
||||
property changed.
|
||||
@@ -43,20 +43,21 @@ entities:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/** @Entity */
|
||||
#[Entity]
|
||||
class Article
|
||||
{
|
||||
const STATUS_VISIBLE = 'visible';
|
||||
const STATUS_INVISIBLE = 'invisible';
|
||||
public const STATUS_VISIBLE = 'visible';
|
||||
public const STATUS_INVISIBLE = 'invisible';
|
||||
|
||||
/** @Column(type="string") */
|
||||
#[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;
|
||||
}
|
||||
}
|
||||
@@ -67,10 +68,10 @@ the **columnDefinition** attribute.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/** @Entity */
|
||||
#[Entity]
|
||||
class Article
|
||||
{
|
||||
/** @Column(type="string", columnDefinition="ENUM('visible', 'invisible')") */
|
||||
#[Column(type: "string", columnDefinition: "ENUM('visible', 'invisible')")]
|
||||
private $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');``.
|
||||
@@ -131,10 +128,10 @@ Then in your entity you can just use this type:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/** @Entity */
|
||||
#[Entity]
|
||||
class Article
|
||||
{
|
||||
/** @Column(type="enumvisibility") */
|
||||
#[Column(type: "enumvisibility")]
|
||||
private $status;
|
||||
}
|
||||
|
||||
@@ -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,6 +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'];
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
|
||||
* that is used for this blockitem. (This string (!) value will be persisted by Doctrine ORM)
|
||||
*
|
||||
* This is a doctrine field, so make sure that you use a
|
||||
#[Column] attribute or setup your yaml or xml files correctly
|
||||
#[Column] attribute or setup your xml files correctly
|
||||
* @var string
|
||||
*/
|
||||
protected $strategyClassName;
|
||||
|
||||
@@ -71,23 +71,6 @@ First Attributes:
|
||||
public function assertCustomerAllowedBuying() {}
|
||||
}
|
||||
|
||||
As Annotations:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @Entity
|
||||
* @HasLifecycleCallbacks
|
||||
*/
|
||||
class Order
|
||||
{
|
||||
/**
|
||||
* @PrePersist @PreUpdate
|
||||
*/
|
||||
public function assertCustomerAllowedBuying() {}
|
||||
}
|
||||
|
||||
In XML Mappings:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
@@ -162,15 +162,13 @@ requiring timezoned datetimes:
|
||||
<?php
|
||||
namespace Shipping;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
#[Entity]
|
||||
class Event
|
||||
{
|
||||
/** @Column(type="datetime") */
|
||||
#[Column(type: 'datetime')]
|
||||
private $created;
|
||||
|
||||
/** @Column(type="string") */
|
||||
#[Column(type: 'string')]
|
||||
private $timezone;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Welcome to Doctrine 2 ORM's documentation!
|
||||
Welcome to Doctrine ORM's documentation!
|
||||
==========================================
|
||||
|
||||
The Doctrine documentation is comprised of tutorials, a reference section and
|
||||
@@ -39,10 +39,8 @@ Mapping Objects onto a Database
|
||||
:doc:`Inheritance <reference/inheritance-mapping>`
|
||||
|
||||
* **Drivers**:
|
||||
:doc:`Docblock Annotations <reference/annotations-reference>` \|
|
||||
:doc:`Attributes <reference/attributes-reference>` \|
|
||||
:doc:`XML <reference/xml-mapping>` \|
|
||||
:doc:`YAML <reference/yaml-mapping>` \|
|
||||
:doc:`PHP <reference/php-mapping>`
|
||||
|
||||
Working with Objects
|
||||
@@ -75,6 +73,7 @@ Advanced Topics
|
||||
* :doc:`TypedFieldMapper <reference/typedfieldmapper>`
|
||||
* :doc:`Improving Performance <reference/improving-performance>`
|
||||
* :doc:`Caching <reference/caching>`
|
||||
* :doc:`Partial Hydration <reference/partial-hydration>`
|
||||
* :doc:`Partial Objects <reference/partial-objects>`
|
||||
* :doc:`Change Tracking Policies <reference/change-tracking-policies>`
|
||||
* :doc:`Best Practices <reference/best-practices>`
|
||||
@@ -103,6 +102,7 @@ Cookbook
|
||||
|
||||
* **Patterns**:
|
||||
:doc:`Aggregate Fields <cookbook/aggregate-fields>` \|
|
||||
:doc:`Generated/Virtual Columns <cookbook/generated-columns>` \|
|
||||
:doc:`Decorator Pattern <cookbook/decorator-pattern>` \|
|
||||
:doc:`Strategy Pattern <cookbook/strategy-cookbook-introduction>`
|
||||
|
||||
@@ -112,7 +112,6 @@ Cookbook
|
||||
|
||||
* **Implementation**:
|
||||
:doc:`Array Access <cookbook/implementing-arrayaccess-for-domain-objects>` \|
|
||||
:doc:`Notify ChangeTracking Example <cookbook/implementing-the-notify-changetracking-policy>` \|
|
||||
:doc:`Working with DateTime <cookbook/working-with-datetime>` \|
|
||||
:doc:`Validation <cookbook/validation-of-entities>` \|
|
||||
:doc:`Entities in the Session <cookbook/entities-in-session>` \|
|
||||
@@ -123,4 +122,5 @@ Cookbook
|
||||
|
||||
* **Custom Datatypes**
|
||||
:doc:`MySQL Enums <cookbook/mysql-enums>`
|
||||
:doc:`Custom Mapping Types <cookbook/custom-mapping-types>`
|
||||
:doc:`Advanced Field Value Conversion <cookbook/advanced-field-value-conversion-using-custom-mapping-types>`
|
||||
|
||||
113
docs/en/make.bat
113
docs/en/make.bat
@@ -1,113 +0,0 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
set SPHINXBUILD=sphinx-build
|
||||
set BUILDDIR=_build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||
del /q /s %BUILDDIR%\*
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Doctrine2ORM.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Doctrine2ORM.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in %BUILDDIR%/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
||||
@@ -19,7 +19,7 @@ steps of configuration.
|
||||
|
||||
// ...
|
||||
|
||||
if ($applicationMode == "development") {
|
||||
if ($applicationMode === "development") {
|
||||
$queryCache = new ArrayAdapter();
|
||||
$metadataCache = new ArrayAdapter();
|
||||
} else {
|
||||
@@ -32,13 +32,18 @@ steps of configuration.
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
$config->setQueryCache($queryCache);
|
||||
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
|
||||
$config->setProxyNamespace('MyProject\Proxies');
|
||||
|
||||
if ($applicationMode == "development") {
|
||||
$config->setAutoGenerateProxyClasses(true);
|
||||
if (PHP_VERSION_ID > 80400) {
|
||||
$config->enableNativeLazyObjects(true);
|
||||
} else {
|
||||
$config->setAutoGenerateProxyClasses(false);
|
||||
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
|
||||
$config->setProxyNamespace('MyProject\Proxies');
|
||||
|
||||
if ($applicationMode === "development") {
|
||||
$config->setAutoGenerateProxyClasses(true);
|
||||
} else {
|
||||
$config->setAutoGenerateProxyClasses(false);
|
||||
}
|
||||
}
|
||||
|
||||
$connection = DriverManager::getConnection([
|
||||
@@ -71,8 +76,25 @@ Configuration Options
|
||||
The following sections describe all the configuration options
|
||||
available on a ``Doctrine\ORM\Configuration`` instance.
|
||||
|
||||
Proxy Directory (***REQUIRED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
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
|
||||
|
||||
@@ -85,8 +107,11 @@ classes. For a detailed explanation on proxy classes and how they
|
||||
are used in Doctrine, refer to the "Proxy Objects" section further
|
||||
down.
|
||||
|
||||
Proxy Namespace (***REQUIRED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Proxy Namespace
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Required except if you use native lazy objects with PHP 8.4.
|
||||
This setting will be removed in the future.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -98,8 +123,8 @@ Gets or sets the namespace to use for generated proxy classes. For
|
||||
a detailed explanation on proxy classes and how they are used in
|
||||
Doctrine, refer to the "Proxy Objects" section further down.
|
||||
|
||||
Metadata Driver (***REQUIRED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Metadata Driver (**REQUIRED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -111,21 +136,16 @@ Gets or sets the metadata driver implementation that is used by
|
||||
Doctrine to acquire the object-relational metadata for your
|
||||
classes.
|
||||
|
||||
There are currently 5 available implementations:
|
||||
There are currently 3 available implementations:
|
||||
|
||||
|
||||
- ``Doctrine\ORM\Mapping\Driver\AttributeDriver``
|
||||
- ``Doctrine\ORM\Mapping\Driver\XmlDriver``
|
||||
- ``Doctrine\ORM\Mapping\Driver\DriverChain``
|
||||
- ``Doctrine\ORM\Mapping\Driver\AnnotationDriver`` (deprecated and will
|
||||
be removed in ``doctrine/orm`` 3.0)
|
||||
- ``Doctrine\ORM\Mapping\Driver\YamlDriver`` (deprecated and will be
|
||||
removed in ``doctrine/orm`` 3.0)
|
||||
|
||||
Throughout the most part of this manual the AttributeDriver is
|
||||
used in the examples. For information on the usage of the
|
||||
AnnotationDriver, XmlDriver or YamlDriver please refer to the dedicated
|
||||
chapters ``Annotation Reference``, ``XML Mapping`` and ``YAML Mapping``.
|
||||
XmlDriver please refer to the dedicated chapter ``XML Mapping``.
|
||||
|
||||
The attribute driver can be injected in the ``Doctrine\ORM\Configuration``:
|
||||
|
||||
@@ -144,8 +164,8 @@ accept either a single directory as a string or an array of
|
||||
directories. With this feature a single driver can support multiple
|
||||
directories of Entities.
|
||||
|
||||
Metadata Cache (***RECOMMENDED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Metadata Cache (**RECOMMENDED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -155,9 +175,9 @@ Metadata Cache (***RECOMMENDED***)
|
||||
|
||||
Gets or sets the cache adapter to use for caching metadata
|
||||
information, that is, all the information you supply via attributes,
|
||||
annotations, xml or yaml, so that they do not need to be parsed and
|
||||
loaded from scratch on every single request which is a waste of
|
||||
resources. The cache implementation must implement the PSR-6
|
||||
xml, so that they do not need to be parsed and loaded from scratch on
|
||||
every single request which is a waste of resources. The cache
|
||||
implementation must implement the PSR-6
|
||||
``Psr\Cache\CacheItemPoolInterface`` interface.
|
||||
|
||||
Usage of a metadata cache is highly recommended.
|
||||
@@ -166,8 +186,8 @@ For development you should use an array cache like
|
||||
``Symfony\Component\Cache\Adapter\ArrayAdapter``
|
||||
which only caches data on a per-request basis.
|
||||
|
||||
Query Cache (***RECOMMENDED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Query Cache (**RECOMMENDED**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -189,8 +209,8 @@ For development you should use an array cache like
|
||||
``Symfony\Component\Cache\Adapter\ArrayAdapter``
|
||||
which only caches data on a per-request basis.
|
||||
|
||||
SQL Logger (***Optional***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
SQL Logger (**Optional**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -202,8 +222,11 @@ Gets or sets the logger to use for logging all SQL statements
|
||||
executed by Doctrine. The logger class must implement the
|
||||
deprecated ``Doctrine\DBAL\Logging\SQLLogger`` interface.
|
||||
|
||||
Auto-generating Proxy Classes (***OPTIONAL***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Auto-generating Proxy Classes (**OPTIONAL**)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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
|
||||
@@ -425,7 +448,7 @@ Multiple Metadata Sources
|
||||
|
||||
When using different components using Doctrine ORM you may end up
|
||||
with them using two different metadata drivers, for example XML and
|
||||
YAML. You can use the MappingDriverChain Metadata implementations to
|
||||
PHP. You can use the MappingDriverChain Metadata implementations to
|
||||
aggregate these drivers based on namespaces:
|
||||
|
||||
.. code-block:: php
|
||||
@@ -435,7 +458,7 @@ aggregate these drivers based on namespaces:
|
||||
|
||||
$chain = new MappingDriverChain();
|
||||
$chain->addDriver($xmlDriver, 'Doctrine\Tests\Models\Company');
|
||||
$chain->addDriver($yamlDriver, 'Doctrine\Tests\ORM\Mapping');
|
||||
$chain->addDriver($phpDriver, 'Doctrine\Tests\ORM\Mapping');
|
||||
|
||||
Based on the namespace of the entity the loading of entities is
|
||||
delegated to the appropriate driver. The chain semantics come from
|
||||
@@ -446,7 +469,7 @@ correctly if sub-namespaces use different metadata driver
|
||||
implementations.
|
||||
|
||||
|
||||
Default Repository (***OPTIONAL***)
|
||||
Default Repository (**OPTIONAL**)
|
||||
-----------------------------------
|
||||
|
||||
Specifies the FQCN of a subclass of the EntityRepository.
|
||||
@@ -461,7 +484,7 @@ That will be available for all entities without a custom repository class.
|
||||
The default value is ``Doctrine\ORM\EntityRepository``.
|
||||
Any repository class must be a subclass of EntityRepository otherwise you got an ORMException
|
||||
|
||||
Ignoring entities (***OPTIONAL***)
|
||||
Ignoring entities (**OPTIONAL**)
|
||||
-----------------------------------
|
||||
|
||||
Specifies the Entity FQCNs to ignore.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ well.
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Doctrine ORM requires a minimum of PHP 7.1. For greatly improved
|
||||
Doctrine ORM requires a minimum of PHP 8.1. For greatly improved
|
||||
performance it is also recommended that you use APC with PHP.
|
||||
|
||||
Doctrine ORM Packages
|
||||
@@ -33,14 +33,13 @@ Doctrine ORM is divided into four main packages.
|
||||
- ORM (depends on DBAL+Persistence+Collections)
|
||||
|
||||
This manual mainly covers the ORM package, sometimes touching parts
|
||||
of the underlying DBAL and Persistence packages. The Doctrine code base
|
||||
is split in to these packages for a few reasons and they are to...
|
||||
of the underlying DBAL and Persistence packages. The Doctrine codebase
|
||||
is split into these packages for a few reasons:
|
||||
|
||||
|
||||
- ...make things more maintainable and decoupled
|
||||
- ...allow you to use the code in Doctrine Persistence and Collections
|
||||
without the ORM or DBAL
|
||||
- ...allow you to use the DBAL without the ORM
|
||||
- to make things more maintainable and decoupled
|
||||
- to allow you to use the code in Doctrine Persistence and Collections without the ORM or DBAL
|
||||
- to allow you to use the DBAL without the ORM
|
||||
|
||||
Collection, Event Manager and Persistence
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -56,27 +56,6 @@ A many-to-one association is the most common association between objects. Exampl
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/** @Entity */
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="Address")
|
||||
* @JoinColumn(name="address_id", referencedColumnName="id")
|
||||
*/
|
||||
private Address|null $address = null;
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class Address
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -87,18 +66,6 @@ A many-to-one association is the most common association between objects. Exampl
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
manyToOne:
|
||||
address:
|
||||
targetEntity: Address
|
||||
joinColumn:
|
||||
name: address_id
|
||||
referencedColumnName: id
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
The above ``#[JoinColumn]`` is optional as it would default
|
||||
@@ -154,30 +121,6 @@ references one ``Shipment`` entity.
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/** @Entity */
|
||||
class Product
|
||||
{
|
||||
// ...
|
||||
|
||||
/**
|
||||
* One Product has One Shipment.
|
||||
* @OneToOne(targetEntity="Shipment")
|
||||
* @JoinColumn(name="shipment_id", referencedColumnName="id")
|
||||
*/
|
||||
private Shipment|null $shipment = null;
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class Shipment
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -188,17 +131,6 @@ references one ``Shipment`` entity.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Product:
|
||||
type: entity
|
||||
oneToOne:
|
||||
shipment:
|
||||
targetEntity: Shipment
|
||||
joinColumn:
|
||||
name: shipment_id
|
||||
referencedColumnName: id
|
||||
|
||||
Note that the ``#[JoinColumn]`` is not really necessary in this example,
|
||||
as the defaults would be the same.
|
||||
|
||||
@@ -259,38 +191,6 @@ object.
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/** @Entity */
|
||||
class Customer
|
||||
{
|
||||
// ...
|
||||
|
||||
/**
|
||||
* One Customer has One Cart.
|
||||
* @OneToOne(targetEntity="Cart", mappedBy="customer")
|
||||
*/
|
||||
private Cart|null $cart = null;
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class Cart
|
||||
{
|
||||
// ...
|
||||
|
||||
/**
|
||||
* One Cart has One Customer.
|
||||
* @OneToOne(targetEntity="Customer", inversedBy="cart")
|
||||
* @JoinColumn(name="customer_id", referencedColumnName="id")
|
||||
*/
|
||||
private Customer|null $customer = null;
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -304,22 +204,6 @@ object.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Customer:
|
||||
oneToOne:
|
||||
cart:
|
||||
targetEntity: Cart
|
||||
mappedBy: customer
|
||||
Cart:
|
||||
oneToOne:
|
||||
customer:
|
||||
targetEntity: Customer
|
||||
inversedBy: cart
|
||||
joinColumn:
|
||||
name: customer_id
|
||||
referencedColumnName: id
|
||||
|
||||
Note that the @JoinColumn is not really necessary in this example,
|
||||
as the defaults would be the same.
|
||||
|
||||
@@ -428,41 +312,6 @@ bidirectional many-to-one.
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
/** @Entity */
|
||||
class Product
|
||||
{
|
||||
// ...
|
||||
/**
|
||||
* One product has many features. This is the inverse side.
|
||||
* @var Collection<int, Feature>
|
||||
* @OneToMany(targetEntity="Feature", mappedBy="product")
|
||||
*/
|
||||
private Collection $features;
|
||||
// ...
|
||||
|
||||
public function __construct() {
|
||||
$this->features = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class Feature
|
||||
{
|
||||
// ...
|
||||
/**
|
||||
* Many features have one product. This is the owning side.
|
||||
* @ManyToOne(targetEntity="Product", inversedBy="features")
|
||||
* @JoinColumn(name="product_id", referencedColumnName="id")
|
||||
*/
|
||||
private Product|null $product = null;
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -476,24 +325,6 @@ bidirectional many-to-one.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Product:
|
||||
type: entity
|
||||
oneToMany:
|
||||
features:
|
||||
targetEntity: Feature
|
||||
mappedBy: product
|
||||
Feature:
|
||||
type: entity
|
||||
manyToOne:
|
||||
product:
|
||||
targetEntity: Product
|
||||
inversedBy: features
|
||||
joinColumn:
|
||||
name: product_id
|
||||
referencedColumnName: id
|
||||
|
||||
Note that the @JoinColumn is not really necessary in this example,
|
||||
as the defaults would be the same.
|
||||
|
||||
@@ -556,39 +387,6 @@ The following example sets up such a unidirectional one-to-many association:
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/** @Entity */
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
|
||||
/**
|
||||
* Many Users have Many Phonenumbers.
|
||||
* @ManyToMany(targetEntity="Phonenumber")
|
||||
* @JoinTable(name="users_phonenumbers",
|
||||
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@JoinColumn(name="phonenumber_id", referencedColumnName="id", unique=true)}
|
||||
* )
|
||||
* @var Collection<int, Phonenumber>
|
||||
*/
|
||||
private Collection $phonenumbers;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->phonenumbers = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class Phonenumber
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -606,24 +404,6 @@ The following example sets up such a unidirectional one-to-many association:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
manyToMany:
|
||||
phonenumbers:
|
||||
targetEntity: Phonenumber
|
||||
joinTable:
|
||||
name: users_phonenumbers
|
||||
joinColumns:
|
||||
user_id:
|
||||
referencedColumnName: id
|
||||
inverseJoinColumns:
|
||||
phonenumber_id:
|
||||
referencedColumnName: id
|
||||
unique: true
|
||||
|
||||
|
||||
Generates the following MySQL Schema:
|
||||
|
||||
.. code-block:: sql
|
||||
@@ -684,33 +464,6 @@ database perspective is known as an adjacency list approach.
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/** @Entity */
|
||||
class Category
|
||||
{
|
||||
// ...
|
||||
/**
|
||||
* One Category has Many Categories.
|
||||
* @OneToMany(targetEntity="Category", mappedBy="parent")
|
||||
* @var Collection<int, Category>
|
||||
*/
|
||||
private Collection $children;
|
||||
|
||||
/**
|
||||
* Many Categories have One Category.
|
||||
* @ManyToOne(targetEntity="Category", inversedBy="children")
|
||||
* @JoinColumn(name="parent_id", referencedColumnName="id")
|
||||
*/
|
||||
private Category|null $parent = null;
|
||||
// ...
|
||||
|
||||
public function __construct() {
|
||||
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -720,19 +473,6 @@ database perspective is known as an adjacency list approach.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Category:
|
||||
type: entity
|
||||
oneToMany:
|
||||
children:
|
||||
targetEntity: Category
|
||||
mappedBy: parent
|
||||
manyToOne:
|
||||
parent:
|
||||
targetEntity: Category
|
||||
inversedBy: children
|
||||
|
||||
Note that the @JoinColumn is not really necessary in this example,
|
||||
as the defaults would be the same.
|
||||
|
||||
@@ -787,38 +527,6 @@ entities:
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/** @Entity */
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
|
||||
/**
|
||||
* Many Users have Many Groups.
|
||||
* @ManyToMany(targetEntity="Group")
|
||||
* @JoinTable(name="users_groups",
|
||||
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}
|
||||
* )
|
||||
* @var Collection<int, Group>
|
||||
*/
|
||||
private Collection $groups;
|
||||
|
||||
// ...
|
||||
|
||||
public function __construct() {
|
||||
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class Group
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -836,22 +544,6 @@ entities:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
manyToMany:
|
||||
groups:
|
||||
targetEntity: Group
|
||||
joinTable:
|
||||
name: users_groups
|
||||
joinColumns:
|
||||
user_id:
|
||||
referencedColumnName: id
|
||||
inverseJoinColumns:
|
||||
group_id:
|
||||
referencedColumnName: id
|
||||
|
||||
Generated MySQL Schema:
|
||||
|
||||
.. code-block:: sql
|
||||
@@ -939,47 +631,6 @@ one is bidirectional.
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/** @Entity */
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
|
||||
/**
|
||||
* Many Users have Many Groups.
|
||||
* @ManyToMany(targetEntity="Group", inversedBy="users")
|
||||
* @JoinTable(name="users_groups")
|
||||
* @var Collection<int, Group>
|
||||
*/
|
||||
private Collection $groups;
|
||||
|
||||
public function __construct() {
|
||||
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
/** @Entity */
|
||||
class Group
|
||||
{
|
||||
// ...
|
||||
/**
|
||||
* Many Groups have Many Users.
|
||||
* @ManyToMany(targetEntity="User", mappedBy="groups")
|
||||
* @var Collection<int, User>
|
||||
*/
|
||||
private Collection $users;
|
||||
|
||||
public function __construct() {
|
||||
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -1001,30 +652,6 @@ one is bidirectional.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
manyToMany:
|
||||
groups:
|
||||
targetEntity: Group
|
||||
inversedBy: users
|
||||
joinTable:
|
||||
name: users_groups
|
||||
joinColumns:
|
||||
user_id:
|
||||
referencedColumnName: id
|
||||
inverseJoinColumns:
|
||||
group_id:
|
||||
referencedColumnName: id
|
||||
|
||||
Group:
|
||||
type: entity
|
||||
manyToMany:
|
||||
users:
|
||||
targetEntity: User
|
||||
mappedBy: groups
|
||||
|
||||
The MySQL schema is exactly the same as for the Many-To-Many
|
||||
uni-directional case above.
|
||||
|
||||
@@ -1172,12 +799,6 @@ As an example, consider this mapping:
|
||||
#[OneToOne(targetEntity: Shipment::class)]
|
||||
private Shipment|null $shipment = null;
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/** @OneToOne(targetEntity="Shipment") */
|
||||
private Shipment|null $shipment = null;
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -1186,14 +807,6 @@ As an example, consider this mapping:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Product:
|
||||
type: entity
|
||||
oneToOne:
|
||||
shipment:
|
||||
targetEntity: Shipment
|
||||
|
||||
This is essentially the same as the following, more verbose,
|
||||
mapping:
|
||||
|
||||
@@ -1207,16 +820,6 @@ mapping:
|
||||
#[JoinColumn(name: 'shipment_id', referencedColumnName: 'id')]
|
||||
private Shipment|null $shipment = null;
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/**
|
||||
* One Product has One Shipment.
|
||||
* @OneToOne(targetEntity="Shipment")
|
||||
* @JoinColumn(name="shipment_id", referencedColumnName="id")
|
||||
*/
|
||||
private Shipment|null $shipment = null;
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -1227,17 +830,6 @@ mapping:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Product:
|
||||
type: entity
|
||||
oneToOne:
|
||||
shipment:
|
||||
targetEntity: Shipment
|
||||
joinColumn:
|
||||
name: shipment_id
|
||||
referencedColumnName: id
|
||||
|
||||
The @JoinTable definition used for many-to-many mappings has
|
||||
similar defaults. As an example, consider this mapping:
|
||||
|
||||
@@ -1255,20 +847,6 @@ similar defaults. As an example, consider this mapping:
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
/**
|
||||
* @ManyToMany(targetEntity="Group")
|
||||
* @var Collection<int, Group>
|
||||
*/
|
||||
private Collection $groups;
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -1277,14 +855,6 @@ similar defaults. As an example, consider this mapping:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
manyToMany:
|
||||
groups:
|
||||
targetEntity: Group
|
||||
|
||||
This is essentially the same as the following, more verbose, mapping:
|
||||
|
||||
.. configuration-block::
|
||||
@@ -1307,25 +877,6 @@ This is essentially the same as the following, more verbose, mapping:
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
/**
|
||||
* Many Users have Many Groups.
|
||||
* @ManyToMany(targetEntity="Group")
|
||||
* @JoinTable(name="User_Group",
|
||||
* joinColumns={@JoinColumn(name="User_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@JoinColumn(name="Group_id", referencedColumnName="id")}
|
||||
* )
|
||||
* @var Collection<int, Group>
|
||||
*/
|
||||
private Collection $groups;
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -1343,22 +894,6 @@ This is essentially the same as the following, more verbose, mapping:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
manyToMany:
|
||||
groups:
|
||||
targetEntity: Group
|
||||
joinTable:
|
||||
name: User_Group
|
||||
joinColumns:
|
||||
User_id:
|
||||
referencedColumnName: id
|
||||
inverseJoinColumns:
|
||||
Group_id:
|
||||
referencedColumnName: id
|
||||
|
||||
In that case, the name of the join table defaults to a combination
|
||||
of the simple, unqualified class names of the participating
|
||||
classes, separated by an underscore character. The names of the
|
||||
@@ -1368,8 +903,7 @@ defaults to "id", just as in one-to-one or many-to-one mappings.
|
||||
|
||||
Additionally, when using typed properties with Doctrine 2.9 or newer
|
||||
you can skip ``targetEntity`` in ``ManyToOne`` and ``OneToOne``
|
||||
associations as they will be set based on type. Also ``nullable``
|
||||
attribute on ``JoinColumn`` will be inherited from PHP type. So that:
|
||||
associations as they will be set based on type. So that:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
@@ -1379,12 +913,6 @@ attribute on ``JoinColumn`` will be inherited from PHP type. So that:
|
||||
#[OneToOne]
|
||||
private Shipment $shipment;
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/** @OneToOne */
|
||||
private Shipment $shipment;
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -1393,13 +921,6 @@ attribute on ``JoinColumn`` will be inherited from PHP type. So that:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Product:
|
||||
type: entity
|
||||
oneToOne:
|
||||
shipment: ~
|
||||
|
||||
Is essentially the same as following:
|
||||
|
||||
.. configuration-block::
|
||||
@@ -1409,7 +930,7 @@ Is essentially the same as following:
|
||||
<?php
|
||||
/** One Product has One Shipment. */
|
||||
#[OneToOne(targetEntity: Shipment::class)]
|
||||
#[JoinColumn(name: 'shipment_id', referencedColumnName: 'id', nullable: false)]
|
||||
#[JoinColumn(name: 'shipment_id', referencedColumnName: 'id')]
|
||||
private Shipment $shipment;
|
||||
|
||||
.. code-block:: annotation
|
||||
@@ -1418,7 +939,7 @@ Is essentially the same as following:
|
||||
/**
|
||||
* One Product has One Shipment.
|
||||
* @OneToOne(targetEntity="Shipment")
|
||||
* @JoinColumn(name="shipment_id", referencedColumnName="id", nullable=false)
|
||||
* @JoinColumn(name="shipment_id", referencedColumnName="id")
|
||||
*/
|
||||
private Shipment $shipment;
|
||||
|
||||
@@ -1427,23 +948,11 @@ Is essentially the same as following:
|
||||
<doctrine-mapping>
|
||||
<entity class="Product">
|
||||
<one-to-one field="shipment" target-entity="Shipment">
|
||||
<join-column name="shipment_id" referenced-column-name="id" nulable=false />
|
||||
<join-column name="shipment_id" referenced-column-name="id" nullable=false />
|
||||
</one-to-one>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Product:
|
||||
type: entity
|
||||
oneToOne:
|
||||
shipment:
|
||||
targetEntity: Shipment
|
||||
joinColumn:
|
||||
name: shipment_id
|
||||
referencedColumnName: id
|
||||
nullable: false
|
||||
|
||||
If you accept these defaults, you can reduce the mapping code to a
|
||||
minimum.
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@ Attributes Reference
|
||||
PHP 8 adds native support for metadata with its "Attributes" feature.
|
||||
Doctrine ORM provides support for mapping metadata using PHP attributes as of version 2.9.
|
||||
|
||||
The attributes metadata support is closely modelled after the already existing
|
||||
annotation metadata supported since the first version 2.0.
|
||||
The attributes metadata support is closely modelled after the already
|
||||
existing and now removed annotation metadata supported since the first
|
||||
version 2.0.
|
||||
|
||||
Index
|
||||
-----
|
||||
@@ -14,7 +15,7 @@ Index
|
||||
- :ref:`#[AttributeOverride] <attrref_attributeoverride>`
|
||||
- :ref:`#[Column] <attrref_column>`
|
||||
- :ref:`#[Cache] <attrref_cache>`
|
||||
- :ref:`#[ChangeTrackingPolicy <attrref_changetrackingpolicy>`
|
||||
- :ref:`#[ChangeTrackingPolicy] <attrref_changetrackingpolicy>`
|
||||
- :ref:`#[CustomIdGenerator] <attrref_customidgenerator>`
|
||||
- :ref:`#[DiscriminatorColumn] <attrref_discriminatorcolumn>`
|
||||
- :ref:`#[DiscriminatorMap] <attrref_discriminatormap>`
|
||||
@@ -174,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``.
|
||||
|
||||
@@ -213,12 +218,15 @@ Optional parameters:
|
||||
- ``check``: Adds a check constraint type to the column (might not
|
||||
be supported by all vendors).
|
||||
|
||||
- **columnDefinition**: DDL SQL snippet that starts after the column
|
||||
- **columnDefinition**: Specify the DDL SQL snippet that starts after the column
|
||||
name and specifies the complete (non-portable!) column definition.
|
||||
This attribute allows to make use of advanced RMDBS features.
|
||||
However you should make careful use of this feature and the
|
||||
consequences. ``SchemaTool`` will not detect changes on the column correctly
|
||||
anymore if you use ``columnDefinition``.
|
||||
However, as this needs to be specified in the DDL native to the database,
|
||||
the resulting schema changes are no longer portable. If you specify a
|
||||
``columnDefinition``, the ``SchemaTool`` ignores all other attributes
|
||||
that are normally used to build the definition DDL. Changes to the
|
||||
``columnDefinition`` are not detected, you will need to manually create a
|
||||
migration to apply changes.
|
||||
|
||||
Additionally you should remember that the ``type``
|
||||
attribute still handles the conversion between PHP and Database
|
||||
@@ -241,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;
|
||||
|
||||
@@ -261,10 +272,11 @@ Examples:
|
||||
)]
|
||||
protected $loginCount;
|
||||
|
||||
// MySQL example: full_name char(41) GENERATED ALWAYS AS (concat(firstname,' ',lastname)),
|
||||
// columnDefinition is raw SQL, not DQL. This example works for MySQL:
|
||||
#[Column(
|
||||
type: "string",
|
||||
name: "user_fullname",
|
||||
columnDefinition: "VARCHAR(255) GENERATED ALWAYS AS (concat(firstname,' ',lastname))",
|
||||
insertable: false,
|
||||
updatable: false
|
||||
)]
|
||||
@@ -310,7 +322,6 @@ Example:
|
||||
Entity,
|
||||
ChangeTrackingPolicy("DEFERRED_IMPLICIT"),
|
||||
ChangeTrackingPolicy("DEFERRED_EXPLICIT"),
|
||||
ChangeTrackingPolicy("NOTIFY")
|
||||
]
|
||||
class User {}
|
||||
|
||||
@@ -366,7 +377,7 @@ Optional parameters:
|
||||
|
||||
- **type**: By default this is string.
|
||||
- **length**: By default this is 255.
|
||||
- **columnDefinition**: By default this is null the definition according to the type will be used. This option allows to override it.
|
||||
- **columnDefinition**: Allows to override how the column is generated. See the "columnDefinition" attribute on :ref:`#[Column] <attrref_column>`
|
||||
- **enumType**: By default this is `null`. Allows to map discriminatorColumn value to PHP enum
|
||||
- **options**: See "options" attribute on :ref:`#[Column] <attrref_column>`.
|
||||
|
||||
@@ -485,9 +496,8 @@ used as default.
|
||||
Optional parameters:
|
||||
|
||||
- **strategy**: Set the name of the identifier generation strategy.
|
||||
Valid values are ``AUTO``, ``SEQUENCE``, ``IDENTITY``, ``UUID``
|
||||
(deprecated), ``CUSTOM`` and ``NONE``.
|
||||
If not specified, the default value is ``AUTO``.
|
||||
Valid values are ``AUTO``, ``SEQUENCE``, ``IDENTITY``, ``CUSTOM`` and
|
||||
``NONE``. If not specified, the default value is ``AUTO``.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -673,13 +683,16 @@ Optional parameters:
|
||||
- **unique**: Determines whether this relation is exclusive between the
|
||||
affected entities and should be enforced as such on the database
|
||||
constraint level. Defaults to false.
|
||||
- **deferrable**: Determines whether this relation constraint can be deferred. Defaults to false.
|
||||
- **nullable**: Determine whether the related entity is required, or if
|
||||
null is an allowed state for the relation. Defaults to true.
|
||||
- **onDelete**: Cascade Action (Database-level)
|
||||
- **columnDefinition**: DDL SQL snippet that starts after the column
|
||||
name and specifies the complete (non-portable!) column definition.
|
||||
This attribute enables the use of advanced RMDBS features. Using
|
||||
this attribute on ``#[JoinColumn]`` is necessary if you need slightly
|
||||
This attribute enables the use of advanced RMDBS features. Note that you
|
||||
need to reference columns by their database name (either explicitly set in
|
||||
the mapping or per the current :doc:`naming strategy <namingstrategy>`).
|
||||
Using this attribute on ``#[JoinColumn]`` is necessary if you need
|
||||
different column definitions for joining columns, for example
|
||||
regarding NULL/NOT NULL defaults. However by default a
|
||||
"columnDefinition" attribute on :ref:`#[Column] <attrref_column>` also sets
|
||||
@@ -712,10 +725,6 @@ details of the database join table. If you do not specify
|
||||
``#[JoinTable]`` on these relations reasonable mapping defaults apply
|
||||
using the affected table and the column names.
|
||||
|
||||
A notable difference to the annotation metadata support, ``#[JoinColumn]``
|
||||
and ``#[InverseJoinColumn]`` can be specified at the property level and are not
|
||||
nested within the ``#[JoinTable]`` attribute.
|
||||
|
||||
Required attribute:
|
||||
|
||||
- **name**: Database name of the join-table
|
||||
@@ -931,7 +940,7 @@ Example:
|
||||
#[OneToMany(
|
||||
targetEntity: "Phonenumber",
|
||||
mappedBy: "user",
|
||||
cascade: ["persist", "remove", "merge"],
|
||||
cascade: ["persist", "remove"],
|
||||
orphanRemoval: true)
|
||||
]
|
||||
public $phonenumbers;
|
||||
@@ -1138,7 +1147,7 @@ Marker attribute that defines a specified column as version attribute used in
|
||||
an :ref:`optimistic locking <transactions-and-concurrency_optimistic-locking>`
|
||||
scenario. It only works on :ref:`#[Column] <attrref_column>` attributes that have
|
||||
the type ``integer`` or ``datetime``. Setting ``#[Version]`` on a property with
|
||||
:ref:`#[Id <attrref_id>` is not supported.
|
||||
:ref:`#[Id] <attrref_id>` is not supported.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -47,17 +47,14 @@ mapping metadata:
|
||||
- :doc:`Attributes <attributes-reference>`
|
||||
- :doc:`XML <xml-mapping>`
|
||||
- :doc:`PHP code <php-mapping>`
|
||||
- :doc:`Docblock Annotations <annotations-reference>` (deprecated and will be removed in ``doctrine/orm`` 3.0)
|
||||
- :doc:`YAML <yaml-mapping>` (deprecated and will be removed in ``doctrine/orm`` 3.0.)
|
||||
|
||||
This manual will usually show mapping metadata via attributes, though
|
||||
many examples also show the equivalent configuration in annotations,
|
||||
YAML and XML.
|
||||
many examples also show the equivalent configuration in XML.
|
||||
|
||||
.. note::
|
||||
|
||||
All metadata drivers perform equally. Once the metadata of a class has been
|
||||
read from the source (attributes, annotations, XML, etc.) it is stored in an instance
|
||||
read from the source (attributes, XML, etc.) it is stored in an instance
|
||||
of the ``Doctrine\ORM\Mapping\ClassMetadata`` class which are
|
||||
stored in the metadata cache. If you're not using a metadata cache (not
|
||||
recommended!) then the XML driver is the fastest.
|
||||
@@ -77,17 +74,6 @@ Marking our ``Message`` class as an entity for Doctrine is straightforward:
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
|
||||
/** @Entity */
|
||||
class Message
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -96,12 +82,6 @@ Marking our ``Message`` class as an entity for Doctrine is straightforward:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Message:
|
||||
type: entity
|
||||
# ...
|
||||
|
||||
With no additional information, Doctrine expects the entity to be saved
|
||||
into a table with the same name as the class in our case ``Message``.
|
||||
You can change this by configuring information about the table:
|
||||
@@ -121,21 +101,6 @@ You can change this by configuring information about the table:
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="message")
|
||||
*/
|
||||
class Message
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -144,13 +109,6 @@ You can change this by configuring information about the table:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Message:
|
||||
type: entity
|
||||
table: message
|
||||
# ...
|
||||
|
||||
Now the class ``Message`` will be saved and fetched from the table ``message``.
|
||||
|
||||
Property Mapping
|
||||
@@ -182,23 +140,6 @@ specified, ``string`` is used as the default.
|
||||
private $postedAt;
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
|
||||
/** @Entity */
|
||||
class Message
|
||||
{
|
||||
/** @Column(type="integer") */
|
||||
private $id;
|
||||
/** @Column(length=140) */
|
||||
private $text;
|
||||
/** @Column(type="datetime", name="posted_at") */
|
||||
private $postedAt;
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -209,19 +150,6 @@ specified, ``string`` is used as the default.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Message:
|
||||
type: entity
|
||||
fields:
|
||||
id:
|
||||
type: integer
|
||||
text:
|
||||
length: 140
|
||||
postedAt:
|
||||
type: datetime
|
||||
column: posted_at
|
||||
|
||||
When we don't explicitly specify a column name via the ``name`` option, Doctrine
|
||||
assumes the field name is also the column name. So in this example:
|
||||
|
||||
@@ -239,6 +167,7 @@ Here is a complete list of ``Column``s attributes (all optional):
|
||||
- ``nullable`` (default: ``false``): Whether the column is nullable.
|
||||
- ``insertable`` (default: ``true``): Whether the column should be inserted.
|
||||
- ``updatable`` (default: ``true``): Whether the column should be updated.
|
||||
- ``generated`` (default: ``null``): Whether the generated strategy should be ``'NEVER'``, ``'INSERT'`` and ``ALWAYS``.
|
||||
- ``enumType`` (requires PHP 8.1 and ``doctrine/orm`` 2.11): The PHP enum class name to convert the database value into.
|
||||
- ``precision`` (default: 0): The precision for a decimal (exact numeric) column
|
||||
(applies only for decimal column),
|
||||
@@ -285,6 +214,8 @@ These are the "automatic" mapping rules:
|
||||
| Any other type | ``Types::STRING`` |
|
||||
+-----------------------+-------------------------------+
|
||||
|
||||
.. versionadded:: 2.11
|
||||
|
||||
As of version 2.11 Doctrine can also automatically map typed properties using a
|
||||
PHP 8.1 enum to set the right ``type`` and ``enumType``.
|
||||
|
||||
@@ -295,6 +226,70 @@ and a custom ``Doctrine\ORM\Mapping\TypedFieldMapper`` implementation.
|
||||
|
||||
:doc:`Read more about TypedFieldMapper <typedfieldmapper>`.
|
||||
|
||||
Property Hooks
|
||||
--------------
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
Doctrine supports mapping hooked properties as long as they have a backed property
|
||||
and are not virtual.
|
||||
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
|
||||
#[Entity]
|
||||
class Message
|
||||
{
|
||||
#[Column(type: Types::INTEGER)]
|
||||
private $id;
|
||||
#[Column(type: Types::STRING)]
|
||||
public string $language = 'de' {
|
||||
// Override the "read" action with arbitrary logic.
|
||||
get => strtoupper($this->language);
|
||||
|
||||
// Override the "write" action with arbitrary logic.
|
||||
set {
|
||||
$this->language = strtolower($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
<entity name="Message">
|
||||
<field name="id" type="integer" />
|
||||
<field name="language" />
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
If you attempt to map a virtual property with ``#[Column]`` an exception will be thrown.
|
||||
|
||||
Some caveats apply to the use of property hooks, as they behave differently when accessing the property through
|
||||
the entity or directly through DQL/EntityRepository. Because the property hook can modify the value of the property in a way
|
||||
that value and raw value are different, you have to use the raw value representation when querying for the property.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$queryBuilder = $entityManager->createQueryBuilder();
|
||||
$queryBuilder->select('m')
|
||||
->from(Message::class, 'm')
|
||||
->where('m.language = :language')
|
||||
->setParameter('language', 'de'); // Use lower case here for raw value representation
|
||||
|
||||
$query = $queryBuilder->getQuery();
|
||||
$result = $query->getResult();
|
||||
|
||||
$messageRepository = $entityManager->getRepository(Message::class);
|
||||
$deMessages = $messageRepository->findBy(['language' => 'de']); // Use lower case here for raw value representation
|
||||
|
||||
.. _reference-mapping-types:
|
||||
|
||||
Doctrine Mapping Types
|
||||
@@ -346,20 +341,6 @@ the field that serves as the identifier with the ``#[Id]`` attribute.
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
class Message
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue
|
||||
*/
|
||||
private int|null $id = null;
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -371,24 +352,27 @@ the field that serves as the identifier with the ``#[Id]`` attribute.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Message:
|
||||
type: entity
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
generator:
|
||||
strategy: AUTO
|
||||
fields:
|
||||
# fields here
|
||||
|
||||
In most cases using the automatic generator strategy (``#[GeneratedValue]``) is
|
||||
what you want, but for backwards-compatibility reasons it might not. It
|
||||
defaults to the identifier generation mechanism your current database
|
||||
vendor preferred at the time that strategy was introduced:
|
||||
``AUTO_INCREMENT`` with MySQL, sequences with PostgreSQL and Oracle and
|
||||
so on.
|
||||
If you are using `doctrine/dbal` 4, we now recommend using ``IDENTITY``
|
||||
for PostgreSQL, and ``AUTO`` resolves to it because of that.
|
||||
You can stick with ``SEQUENCE`` while still using the ``AUTO``
|
||||
strategy, by configuring what it defaults to.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
|
||||
use Doctrine\ORM\Configuration;
|
||||
|
||||
$config = new Configuration();
|
||||
$config->setIdentityGenerationPreferences([
|
||||
PostgreSQLPlatform::class => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
|
||||
]);
|
||||
|
||||
.. _identifier-generation-strategies:
|
||||
|
||||
@@ -417,14 +401,12 @@ Here is the list of possible generation strategies:
|
||||
generation. This strategy does currently not provide full
|
||||
portability. Sequences are supported by Oracle, PostgreSql and
|
||||
SQL Anywhere.
|
||||
- ``UUID`` (deprecated): Tells Doctrine to use the built-in Universally
|
||||
Unique Identifier generator. This strategy provides full portability.
|
||||
- ``NONE``: Tells Doctrine that the identifiers are assigned (and
|
||||
thus generated) by your code. The assignment must take place before
|
||||
a new entity is passed to ``EntityManager#persist``. NONE is the
|
||||
same as leaving off the ``#[GeneratedValue]`` entirely.
|
||||
- ``CUSTOM``: With this option, you can use the ``#[CustomIdGenerator]`` attribute.
|
||||
It will allow you to pass a :ref:`class of your own to generate the identifiers. <annref_customidgenerator>`
|
||||
It will allow you to pass a :ref:`class of your own to generate the identifiers. <attrref_customidgenerator>`
|
||||
|
||||
Sequence Generator
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
@@ -447,20 +429,6 @@ besides specifying the sequence's name:
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
class Message
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @GeneratedValue(strategy="SEQUENCE")
|
||||
* @SequenceGenerator(sequenceName="message_seq", initialValue=1, allocationSize=100)
|
||||
*/
|
||||
protected int|null $id = null;
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -472,20 +440,6 @@ besides specifying the sequence's name:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Message:
|
||||
type: entity
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
generator:
|
||||
strategy: SEQUENCE
|
||||
sequenceGenerator:
|
||||
sequenceName: message_seq
|
||||
allocationSize: 100
|
||||
initialValue: 1
|
||||
|
||||
The initial value specifies at which value the sequence should
|
||||
start.
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ should use events judiciously.
|
||||
Use cascades judiciously
|
||||
------------------------
|
||||
|
||||
Automatic cascades of the persist/remove/merge/etc. operations are
|
||||
Automatic cascades of the persist/remove/etc. operations are
|
||||
very handy but should be used wisely. Do NOT simply add all
|
||||
cascades to all associations. Think about which cascades actually
|
||||
do make sense for you for a particular association, given the
|
||||
|
||||
@@ -109,7 +109,7 @@ Metadata Cache
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Your class metadata can be parsed from a few different sources like
|
||||
YAML, XML, Attributes, Annotations etc. Instead of parsing this
|
||||
XML, Attributes, etc. Instead of parsing this
|
||||
information on each request we should cache it using one of the cache
|
||||
drivers.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Change tracking is the process of determining what has changed in
|
||||
managed entities since the last time they were synchronized with
|
||||
the database.
|
||||
|
||||
Doctrine provides 3 different change tracking policies, each having
|
||||
Doctrine provides 2 different change tracking policies, each having
|
||||
its particular advantages and disadvantages. The change tracking
|
||||
policy can be defined on a per-class basis (or more precisely,
|
||||
per-hierarchy).
|
||||
@@ -56,122 +56,3 @@ This policy can be configured as follows:
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
Notify
|
||||
~~~~~~
|
||||
|
||||
.. note::
|
||||
|
||||
The notify change tracking policy is deprecated and will be removed in ORM 3.0.
|
||||
(\ `Details <https://github.com/doctrine/orm/issues/8383>`_)
|
||||
|
||||
This policy is based on the assumption that the entities notify
|
||||
interested listeners of changes to their properties. For that
|
||||
purpose, a class that wants to use this policy needs to implement
|
||||
the ``NotifyPropertyChanged`` interface from the Doctrine
|
||||
namespace. As a guideline, such an implementation can look as
|
||||
follows:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\Persistence\NotifyPropertyChanged,
|
||||
Doctrine\Persistence\PropertyChangedListener;
|
||||
|
||||
#[Entity]
|
||||
#[ChangeTrackingPolicy('NOTIFY')]
|
||||
class MyEntity implements NotifyPropertyChanged
|
||||
{
|
||||
// ...
|
||||
|
||||
private array $_listeners = array();
|
||||
|
||||
public function addPropertyChangedListener(PropertyChangedListener $listener): void
|
||||
{
|
||||
$this->_listeners[] = $listener;
|
||||
}
|
||||
}
|
||||
|
||||
Then, in each property setter of this class or derived classes, you
|
||||
need to notify all the ``PropertyChangedListener`` instances. As an
|
||||
example we add a convenience method on ``MyEntity`` that shows this
|
||||
behaviour:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// ...
|
||||
|
||||
class MyEntity implements NotifyPropertyChanged
|
||||
{
|
||||
// ...
|
||||
|
||||
protected function _onPropertyChanged($propName, $oldValue, $newValue): void
|
||||
{
|
||||
if ($this->_listeners) {
|
||||
foreach ($this->_listeners as $listener) {
|
||||
$listener->propertyChanged($this, $propName, $oldValue, $newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setData($data): void
|
||||
{
|
||||
if ($data != $this->data) {
|
||||
$this->_onPropertyChanged('data', $this->data, $data);
|
||||
$this->data = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
You have to invoke ``_onPropertyChanged`` inside every method that
|
||||
changes the persistent state of ``MyEntity``.
|
||||
|
||||
The check whether the new value is different from the old one is
|
||||
not mandatory but recommended. That way you also have full control
|
||||
over when you consider a property changed.
|
||||
|
||||
If your entity contains an embeddable, you will need to notify
|
||||
separately for each property in the embeddable when it changes
|
||||
for example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// ...
|
||||
|
||||
class MyEntity implements NotifyPropertyChanged
|
||||
{
|
||||
public function setEmbeddable(MyValueObject $embeddable): void
|
||||
{
|
||||
if (!$embeddable->equals($this->embeddable)) {
|
||||
// notice the entityField.embeddableField notation for referencing the property
|
||||
$this->_onPropertyChanged('embeddable.prop1', $this->embeddable->getProp1(), $embeddable->getProp1());
|
||||
$this->_onPropertyChanged('embeddable.prop2', $this->embeddable->getProp2(), $embeddable->getProp2());
|
||||
$this->embeddable = $embeddable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
This would update all the fields of the embeddable, you may wish to
|
||||
implement a diff method on your embedded object which returns only
|
||||
the changed fields.
|
||||
|
||||
The negative point of this policy is obvious: You need implement an
|
||||
interface and write some plumbing code. But also note that we tried
|
||||
hard to keep this notification functionality abstract. Strictly
|
||||
speaking, it has nothing to do with the persistence layer and the
|
||||
Doctrine ORM or DBAL. You may find that property notification
|
||||
events come in handy in many other scenarios as well. As mentioned
|
||||
earlier, the ``Doctrine\Common`` namespace is not that evil and
|
||||
consists solely of very small classes and interfaces that have
|
||||
almost no external dependencies (none to the DBAL and none to the
|
||||
ORM) and that you can easily take with you should you want to swap
|
||||
out the persistence layer. This change tracking policy does not
|
||||
introduce a dependency on the Doctrine DBAL/ORM or the persistence
|
||||
layer.
|
||||
|
||||
The positive point and main advantage of this policy is its
|
||||
effectiveness. It has the best performance characteristics of the 3
|
||||
policies with larger units of work and a flush() operation is very
|
||||
cheap when nothing has changed.
|
||||
|
||||
@@ -56,42 +56,22 @@ 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);
|
||||
|
||||
.. note::
|
||||
|
||||
The ``ORMSetup`` class has been introduced with ORM 2.12. It's predecessor ``Setup`` is deprecated and will
|
||||
be removed in version 3.0.
|
||||
|
||||
Or if you prefer XML:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?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);
|
||||
|
||||
Or if you prefer YAML:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$paths = ['/path/to/yml-mappings'];
|
||||
$config = ORMSetup::createYAMLMetadataConfiguration($paths, $isDevMode);
|
||||
$connection = DriverManager::getConnection($dbParams, $config);
|
||||
$entityManager = new EntityManager($connection, $config);
|
||||
|
||||
.. note::
|
||||
If you want to use yml mapping you should add yaml dependency to your `composer.json`:
|
||||
|
||||
::
|
||||
|
||||
"symfony/yaml": "*"
|
||||
|
||||
Inside the ``ORMSetup`` methods several assumptions are made:
|
||||
|
||||
- If ``$isDevMode`` is true caching is done in memory with the ``ArrayAdapter``. Proxy objects are recreated on every request.
|
||||
|
||||
@@ -524,8 +524,8 @@ when the DQL is switched to an arbitrary join.
|
||||
aggregation (GROUP BY)
|
||||
|
||||
|
||||
Partial Object Syntax
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
Partial Hydration Syntax
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
By default when you run a DQL query in Doctrine and select only a
|
||||
subset of the fields for a given entity, you do not receive objects
|
||||
@@ -533,7 +533,7 @@ back. Instead, you receive only arrays as a flat rectangular result
|
||||
set, similar to how you would if you were just using SQL directly
|
||||
and joining some data.
|
||||
|
||||
If you want to select partial objects you can use the ``partial``
|
||||
If you want to select partial objects or fields in array hydration you can use the ``partial``
|
||||
DQL keyword:
|
||||
|
||||
.. code-block:: php
|
||||
@@ -542,12 +542,13 @@ DQL keyword:
|
||||
$query = $em->createQuery('SELECT partial u.{id, username} FROM CmsUser u');
|
||||
$users = $query->getResult(); // array of partially loaded CmsUser objects
|
||||
|
||||
You use the partial syntax when joining as well:
|
||||
You can use the partial syntax when joining as well:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT partial u.{id, username}, partial a.{id, name} FROM CmsUser u JOIN u.articles a');
|
||||
$usersArray = $query->getArrayResult(); // array of partially loaded CmsUser and CmsArticle fields
|
||||
$users = $query->getResult(); // array of partially loaded CmsUser objects
|
||||
|
||||
"NEW" Operator Syntax
|
||||
@@ -587,7 +588,101 @@ And then use the ``NEW`` DQL keyword :
|
||||
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, a.city, SUM(o.value)) FROM Customer c JOIN c.email e JOIN c.address a JOIN c.orders o GROUP BY c');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
Note that you can only pass scalar expressions to the constructor.
|
||||
You can also nest several DTO :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class CustomerDTO
|
||||
{
|
||||
public function __construct(string $name, string $email, AddressDTO $address, string|null $value = null)
|
||||
{
|
||||
// Bind values to the object properties.
|
||||
}
|
||||
}
|
||||
|
||||
class AddressDTO
|
||||
{
|
||||
public function __construct(string $street, string $city, string $zip)
|
||||
{
|
||||
// Bind values to the object properties.
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, NEW AddressDTO(a.street, a.city, a.zip)) FROM Customer c JOIN c.email e JOIN c.address a');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
Note that you can only pass scalar expressions or other Data Transfer Objects to the constructor.
|
||||
|
||||
If you use your data transfer objects for multiple queries, and you would rather not have to
|
||||
specify arguments that precede the ones you are really interested in, you can use named arguments.
|
||||
|
||||
Consider the following DTO, which uses optional arguments:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
class CustomerDTO
|
||||
{
|
||||
public function __construct(
|
||||
public string|null $name = null,
|
||||
public string|null $email = null,
|
||||
public string|null $city = null,
|
||||
public mixed|null $value = null,
|
||||
public AddressDTO|null $address = null,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
You can specify arbitrary arguments in an arbitrary order by using the named argument syntax, and the ORM will try to match argument names with the selected column names.
|
||||
The syntax relies on the NAMED keyword, like so:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT NEW NAMED CustomerDTO(a.city, c.name) FROM Customer c JOIN c.address a');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
// CustomerDTO => {name : 'SMITH', email: null, city: 'London', value: null}
|
||||
|
||||
ORM will also give precedence to column aliases over column names :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT NEW NAMED CustomerDTO(c.name, CONCAT(a.city, ' ' , a.zip) AS value) FROM Customer c JOIN c.address a');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
// CustomerDTO => {name : 'DOE', email: null, city: null, value: 'New York 10011'}
|
||||
|
||||
To define a custom name for a DTO constructor argument, you can either alias the column with the ``AS`` keyword.
|
||||
|
||||
The ``NAMED`` keyword must precede all DTO you want to instantiate :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT NEW NAMED CustomerDTO(c.name, NEW NAMED AddressDTO(a.street, a.city, a.zip) AS address) FROM Customer c JOIN c.address a');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
// CustomerDTO => {name : 'DOE', email: null, city: null, value: 'New York 10011'}
|
||||
|
||||
If two arguments have the same name, a ``DuplicateFieldException`` is thrown.
|
||||
If a field cannot be matched with a property name, a ``NoMatchingPropertyException`` is thrown. This typically happens when using functions without aliasing them.
|
||||
|
||||
You can hydrate an entity nested in a DTO :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, a AS address) FROM Customer c JOIN c.address a');
|
||||
$users = $query->getResult(); // array of CustomerDTO
|
||||
|
||||
// CustomerDTO => {name : 'DOE', email: null, address : {city: 'New York', zip: '10011', address: 'Abbey Road'}
|
||||
|
||||
Using INDEX BY
|
||||
~~~~~~~~~~~~~~
|
||||
@@ -1516,8 +1611,8 @@ Identifiers
|
||||
/* Alias Identification declaration (the "u" of "FROM User u") */
|
||||
AliasIdentificationVariable :: = identifier
|
||||
|
||||
/* identifier that must be a class name (the "User" of "FROM User u"), possibly as a fully qualified class name or namespace-aliased */
|
||||
AbstractSchemaName ::= fully_qualified_name | aliased_name | identifier
|
||||
/* identifier that must be a class name (the "User" of "FROM User u"), possibly as a fully qualified class name */
|
||||
AbstractSchemaName ::= fully_qualified_name | identifier
|
||||
|
||||
/* Alias ResultVariable declaration (the "total" of "COUNT(*) AS total") */
|
||||
AliasResultVariable = identifier
|
||||
@@ -1612,12 +1707,13 @@ Select Expressions
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
SelectExpression ::= (IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression | NewObjectExpression) [["AS"] ["HIDDEN"] AliasResultVariable]
|
||||
SimpleSelectExpression ::= (StateFieldPathExpression | IdentificationVariable | FunctionDeclaration | AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable]
|
||||
PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
|
||||
PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
|
||||
NewObjectExpression ::= "NEW" AbstractSchemaName "(" NewObjectArg {"," NewObjectArg}* ")"
|
||||
NewObjectArg ::= ScalarExpression | "(" Subselect ")"
|
||||
SelectExpression ::= (IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression | NewObjectExpression) [["AS"] ["HIDDEN"] AliasResultVariable]
|
||||
SimpleSelectExpression ::= (StateFieldPathExpression | IdentificationVariable | FunctionDeclaration | AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable]
|
||||
PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
|
||||
PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
|
||||
NewObjectExpression ::= "NEW" AbstractSchemaName "(" NewObjectArg {"," NewObjectArg}* ")"
|
||||
NewObjectArg ::= (ScalarExpression | "(" Subselect ")" | NewObjectExpression | EntityAsDtoArgumentExpression) ["AS" AliasResultVariable]
|
||||
EntityAsDtoArgumentExpression ::= IdentificationVariable
|
||||
|
||||
Conditional Expressions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -260,46 +260,12 @@ specific to a particular entity class's lifecycle.
|
||||
$this->value = 'changed from preUpdate callback!';
|
||||
}
|
||||
}
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PrePersistEventArgs;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @HasLifecycleCallbacks
|
||||
*/
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
|
||||
/** @Column(type="string", length=255) */
|
||||
public $value;
|
||||
|
||||
/** @PrePersist */
|
||||
public function doStuffOnPrePersist(PrePersistEventArgs $eventArgs)
|
||||
{
|
||||
$this->createdAt = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
/** @PrePersist */
|
||||
public function doOtherStuffOnPrePersist()
|
||||
{
|
||||
$this->value = 'changed from prePersist callback!';
|
||||
}
|
||||
|
||||
/** @PreUpdate */
|
||||
public function doStuffOnPreUpdate(PreUpdateEventArgs $eventArgs)
|
||||
{
|
||||
$this->value = 'changed from preUpdate callback!';
|
||||
}
|
||||
}
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="User">
|
||||
@@ -311,17 +277,6 @@ specific to a particular entity class's lifecycle.
|
||||
</lifecycle-callbacks>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
fields:
|
||||
# ...
|
||||
value:
|
||||
type: string(255)
|
||||
lifecycleCallbacks:
|
||||
prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersist ]
|
||||
preUpdate: [ doStuffOnPreUpdate ]
|
||||
|
||||
Lifecycle Callbacks Event Argument
|
||||
----------------------------------
|
||||
@@ -794,16 +749,6 @@ An entity listener is a lifecycle listener class used for an entity.
|
||||
{
|
||||
// ....
|
||||
}
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
namespace MyProject\Entity;
|
||||
|
||||
/** @Entity @EntityListeners({"UserListener"}) */
|
||||
class User
|
||||
{
|
||||
// ....
|
||||
}
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -814,13 +759,6 @@ An entity listener is a lifecycle listener class used for an entity.
|
||||
<!-- .... -->
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
MyProject\Entity\User:
|
||||
type: entity
|
||||
entityListeners:
|
||||
UserListener:
|
||||
# ....
|
||||
|
||||
.. _reference-entity-listeners:
|
||||
|
||||
@@ -893,45 +831,6 @@ you need to map the listener method using the event type mapping:
|
||||
public function postLoadHandler(User $user, PostLoadEventArgs $event): void { // ... }
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PostLoadEventArgs;
|
||||
use Doctrine\ORM\Event\PostPersistEventArgs;
|
||||
use Doctrine\ORM\Event\PostRemoveEventArgs;
|
||||
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
||||
use Doctrine\ORM\Event\PreFlushEventArgs;
|
||||
use Doctrine\ORM\Event\PrePersistEventArgs;
|
||||
use Doctrine\ORM\Event\PreRemoveEventArgs;
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
class UserListener
|
||||
{
|
||||
/** @PrePersist */
|
||||
public function prePersistHandler(User $user, PrePersistEventArgs $event): void { // ... }
|
||||
|
||||
/** @PostPersist */
|
||||
public function postPersistHandler(User $user, PostPersistEventArgs $event): void { // ... }
|
||||
|
||||
/** @PreUpdate */
|
||||
public function preUpdateHandler(User $user, PreUpdateEventArgs $event): void { // ... }
|
||||
|
||||
/** @PostUpdate */
|
||||
public function postUpdateHandler(User $user, PostUpdateEventArgs $event): void { // ... }
|
||||
|
||||
/** @PostRemove */
|
||||
public function postRemoveHandler(User $user, PostRemoveEventArgs $event): void { // ... }
|
||||
|
||||
/** @PreRemove */
|
||||
public function preRemoveHandler(User $user, PreRemoveEventArgs $event): void { // ... }
|
||||
|
||||
/** @PreFlush */
|
||||
public function preFlushHandler(User $user, PreFlushEventArgs $event): void { // ... }
|
||||
|
||||
/** @PostLoad */
|
||||
public function postLoadHandler(User $user, PostLoadEventArgs $event): void { // ... }
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -954,24 +853,6 @@ you need to map the listener method using the event type mapping:
|
||||
<!-- .... -->
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
MyProject\Entity\User:
|
||||
type: entity
|
||||
entityListeners:
|
||||
UserListener:
|
||||
preFlush: [preFlushHandler]
|
||||
postLoad: [postLoadHandler]
|
||||
|
||||
postPersist: [postPersistHandler]
|
||||
prePersist: [prePersistHandler]
|
||||
|
||||
postUpdate: [postUpdateHandler]
|
||||
preUpdate: [preUpdateHandler]
|
||||
|
||||
postRemove: [postRemoveHandler]
|
||||
preRemove: [preRemoveHandler]
|
||||
# ....
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -994,7 +875,8 @@ Specifying an entity listener instance :
|
||||
|
||||
// User.php
|
||||
|
||||
/** @Entity @EntityListeners({"UserListener"}) */
|
||||
#[Entity]
|
||||
#[EntityListeners(["UserListener"])
|
||||
class User
|
||||
{
|
||||
// ....
|
||||
@@ -1052,7 +934,7 @@ Load ClassMetadata Event
|
||||
|
||||
``loadClassMetadata`` - The ``loadClassMetadata`` event occurs after the
|
||||
mapping metadata for a class has been loaded from a mapping source
|
||||
(attributes/annotations/xml/yaml) in to a ``Doctrine\ORM\Mapping\ClassMetadata`` instance.
|
||||
(attributes/xml) in to a ``Doctrine\ORM\Mapping\ClassMetadata`` instance.
|
||||
You can hook in to this process and manipulate the instance.
|
||||
This event is not a lifecycle callback.
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ is common to multiple entity classes.
|
||||
Mapped superclasses, just as regular, non-mapped classes, can
|
||||
appear in the middle of an otherwise mapped inheritance hierarchy
|
||||
(through Single Table Inheritance or Class Table Inheritance). They
|
||||
are not query-able, and need not have an ``#[Id]`` property.
|
||||
are not query-able, and do not require an ``#[Id]`` property.
|
||||
|
||||
No database table will be created for a mapped superclass itself,
|
||||
only for entity classes inheriting from it. That implies that a
|
||||
@@ -208,44 +208,6 @@ Example:
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
namespace MyProject\Model;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("SINGLE_TABLE")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
|
||||
*/
|
||||
class Person
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class Employee extends Person
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
MyProject\Model\Person:
|
||||
type: entity
|
||||
inheritanceType: SINGLE_TABLE
|
||||
discriminatorColumn:
|
||||
name: discr
|
||||
type: string
|
||||
discriminatorMap:
|
||||
person: Person
|
||||
employee: Employee
|
||||
|
||||
MyProject\Model\Employee:
|
||||
type: entity
|
||||
|
||||
In this example, the ``#[DiscriminatorMap]`` specifies that in the
|
||||
discriminator column, a value of "person" identifies a row as being of type
|
||||
@@ -439,58 +401,6 @@ Example:
|
||||
{
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
// user mapping
|
||||
namespace MyProject\Model;
|
||||
/**
|
||||
* @MappedSuperclass
|
||||
*/
|
||||
class User
|
||||
{
|
||||
// other fields mapping
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="Group", inversedBy="users")
|
||||
* @JoinTable(name="users_groups",
|
||||
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
|
||||
* inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}
|
||||
* )
|
||||
* @var Collection<int, Group>
|
||||
*/
|
||||
protected Collection $groups;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="Address")
|
||||
* @JoinColumn(name="address_id", referencedColumnName="id")
|
||||
*/
|
||||
protected Address|null $address = null;
|
||||
}
|
||||
|
||||
// admin mapping
|
||||
namespace MyProject\Model;
|
||||
/**
|
||||
* @Entity
|
||||
* @AssociationOverrides({
|
||||
* @AssociationOverride(name="groups",
|
||||
* joinTable=@JoinTable(
|
||||
* name="users_admingroups",
|
||||
* joinColumns=@JoinColumn(name="adminuser_id"),
|
||||
* inverseJoinColumns=@JoinColumn(name="admingroup_id")
|
||||
* )
|
||||
* ),
|
||||
* @AssociationOverride(name="address",
|
||||
* joinColumns=@JoinColumn(
|
||||
* name="adminaddress_id", referencedColumnName="id"
|
||||
* )
|
||||
* )
|
||||
* })
|
||||
*/
|
||||
class Admin extends User
|
||||
{
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- user mapping -->
|
||||
@@ -500,7 +410,6 @@ Example:
|
||||
<many-to-many field="groups" target-entity="Group" inversed-by="users">
|
||||
<cascade>
|
||||
<cascade-persist/>
|
||||
<cascade-merge/>
|
||||
<cascade-detach/>
|
||||
</cascade>
|
||||
<join-table name="users_groups">
|
||||
@@ -537,51 +446,6 @@ Example:
|
||||
</association-overrides>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
# user mapping
|
||||
MyProject\Model\User:
|
||||
type: mappedSuperclass
|
||||
# other fields mapping
|
||||
manyToOne:
|
||||
address:
|
||||
targetEntity: Address
|
||||
joinColumn:
|
||||
name: address_id
|
||||
referencedColumnName: id
|
||||
cascade: [ persist, merge ]
|
||||
manyToMany:
|
||||
groups:
|
||||
targetEntity: Group
|
||||
joinTable:
|
||||
name: users_groups
|
||||
joinColumns:
|
||||
user_id:
|
||||
referencedColumnName: id
|
||||
inverseJoinColumns:
|
||||
group_id:
|
||||
referencedColumnName: id
|
||||
cascade: [ persist, merge, detach ]
|
||||
|
||||
# admin mapping
|
||||
MyProject\Model\Admin:
|
||||
type: entity
|
||||
associationOverride:
|
||||
address:
|
||||
joinColumn:
|
||||
adminaddress_id:
|
||||
name: adminaddress_id
|
||||
referencedColumnName: id
|
||||
groups:
|
||||
joinTable:
|
||||
name: users_admingroups
|
||||
joinColumns:
|
||||
adminuser_id:
|
||||
referencedColumnName: id
|
||||
inverseJoinColumns:
|
||||
admingroup_id:
|
||||
referencedColumnName: id
|
||||
|
||||
|
||||
Things to note:
|
||||
|
||||
@@ -645,51 +509,6 @@ Could be used by an entity that extends a mapped superclass to override a field
|
||||
{
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
// user mapping
|
||||
namespace MyProject\Model;
|
||||
/**
|
||||
* @MappedSuperclass
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/** @Id @GeneratedValue @Column(type="integer", name="user_id", length=150) */
|
||||
protected int|null $id = null;
|
||||
|
||||
/** @Column(name="user_name", nullable=true, unique=false, length=250) */
|
||||
protected string $name;
|
||||
|
||||
// other fields mapping
|
||||
}
|
||||
|
||||
// guest mapping
|
||||
namespace MyProject\Model;
|
||||
/**
|
||||
* @Entity
|
||||
* @AttributeOverrides({
|
||||
* @AttributeOverride(name="id",
|
||||
* column=@Column(
|
||||
* name = "guest_id",
|
||||
* type = "integer",
|
||||
* length = 140
|
||||
* )
|
||||
* ),
|
||||
* @AttributeOverride(name="name",
|
||||
* column=@Column(
|
||||
* name = "guest_name",
|
||||
* nullable = false,
|
||||
* unique = true,
|
||||
* length = 240
|
||||
* )
|
||||
* )
|
||||
* })
|
||||
*/
|
||||
class Guest extends User
|
||||
{
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- user mapping -->
|
||||
@@ -702,7 +521,6 @@ Could be used by an entity that extends a mapped superclass to override a field
|
||||
<many-to-one field="address" target-entity="Address">
|
||||
<cascade>
|
||||
<cascade-persist/>
|
||||
<cascade-merge/>
|
||||
</cascade>
|
||||
<join-column name="address_id" referenced-column-name="id"/>
|
||||
</many-to-one>
|
||||
@@ -723,42 +541,6 @@ Could be used by an entity that extends a mapped superclass to override a field
|
||||
</attribute-overrides>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
# user mapping
|
||||
MyProject\Model\User:
|
||||
type: mappedSuperclass
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
column: user_id
|
||||
length: 150
|
||||
generator:
|
||||
strategy: AUTO
|
||||
fields:
|
||||
name:
|
||||
type: string
|
||||
column: user_name
|
||||
length: 250
|
||||
nullable: true
|
||||
unique: false
|
||||
#other fields mapping
|
||||
|
||||
|
||||
# guest mapping
|
||||
MyProject\Model\Guest:
|
||||
type: entity
|
||||
attributeOverride:
|
||||
id:
|
||||
column: guest_id
|
||||
type: integer
|
||||
length: 140
|
||||
name:
|
||||
column: guest_name
|
||||
type: string
|
||||
length: 240
|
||||
nullable: false
|
||||
unique: true
|
||||
|
||||
Things to note:
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
:orphan:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
|
||||
@@ -65,15 +65,6 @@ Where the ``attribute_name`` column contains the key and
|
||||
The feature request for persistence of primitive value arrays
|
||||
`is described in the DDC-298 ticket <https://github.com/doctrine/orm/issues/3743>`_.
|
||||
|
||||
Cascade Merge with Bi-directional Associations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There are two bugs now that concern the use of cascade merge in combination with bi-directional associations.
|
||||
Make sure to study the behavior of cascade merge if you are using it:
|
||||
|
||||
- `DDC-875 <https://github.com/doctrine/orm/issues/5398>`_ Merge can sometimes add the same entity twice into a collection
|
||||
- `DDC-763 <https://github.com/doctrine/orm/issues/5277>`_ Cascade merge on associated entities can insert too many rows through "Persistence by Reachability"
|
||||
|
||||
Custom Persisters
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -16,13 +16,6 @@ metadata:
|
||||
- **Attributes** (AttributeDriver)
|
||||
- **PHP Code in files or static functions** (PhpDriver)
|
||||
|
||||
There are also two deprecated ways to do this:
|
||||
|
||||
- **Class DocBlock Annotations** (AnnotationDriver)
|
||||
- **YAML files** (YamlDriver)
|
||||
|
||||
They will be removed in 3.0, make sure to avoid them.
|
||||
|
||||
Something important to note about the above drivers is they are all
|
||||
an intermediate step to the same end result. The mapping
|
||||
information is populated to ``Doctrine\ORM\Mapping\ClassMetadata``
|
||||
@@ -44,11 +37,7 @@ an entity.
|
||||
$em->getConfiguration()->setMetadataCacheImpl(new ApcuCache());
|
||||
|
||||
|
||||
If you want to use one of the included core metadata drivers you need to
|
||||
configure it. If you pick the annotation driver despite it being
|
||||
deprecated, you will additionally need to install
|
||||
``doctrine/annotations``. All the drivers are in the
|
||||
``Doctrine\ORM\Mapping\Driver`` namespace:
|
||||
All the drivers are in the ``Doctrine\ORM\Mapping\Driver`` namespace:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -81,8 +70,8 @@ implements the ``MappingDriver`` interface:
|
||||
/**
|
||||
* Loads the metadata for the specified class into the provided container.
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -93,8 +82,7 @@ implements the ``MappingDriver`` interface:
|
||||
/**
|
||||
* Gets the names of all mapped classes known to this driver.
|
||||
*
|
||||
* @return array<int, string> The names of all mapped classes known to this driver.
|
||||
* @psalm-return list<class-string>
|
||||
* @return list<class-string> The names of all mapped classes known to this driver.
|
||||
*/
|
||||
public function getAllClassNames();
|
||||
|
||||
@@ -102,7 +90,7 @@ implements the ``MappingDriver`` interface:
|
||||
* Returns whether the class with the specified name should have its metadata loaded.
|
||||
* This is only the case if it is either mapped as an Entity or a MappedSuperclass.
|
||||
*
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -110,28 +110,28 @@ You need to create a class which implements ``Doctrine\ORM\Mapping\NamingStrateg
|
||||
<?php
|
||||
class MyAppNamingStrategy implements NamingStrategy
|
||||
{
|
||||
public function classToTableName($className)
|
||||
public function classToTableName(string $className): string
|
||||
{
|
||||
return 'MyApp_' . substr($className, strrpos($className, '\\') + 1);
|
||||
}
|
||||
public function propertyToColumnName($propertyName)
|
||||
public function propertyToColumnName(string $propertyName): string
|
||||
{
|
||||
return $propertyName;
|
||||
}
|
||||
public function referenceColumnName()
|
||||
public function referenceColumnName(): string
|
||||
{
|
||||
return 'id';
|
||||
}
|
||||
public function joinColumnName($propertyName, $className = null)
|
||||
public function joinColumnName(string $propertyName, ?string $className = null): string
|
||||
{
|
||||
return $propertyName . '_' . $this->referenceColumnName();
|
||||
}
|
||||
public function joinTableName($sourceEntity, $targetEntity, $propertyName = null)
|
||||
public function joinTableName(string $sourceEntity, string $targetEntity, string $propertyName): string
|
||||
{
|
||||
return strtolower($this->classToTableName($sourceEntity) . '_' .
|
||||
$this->classToTableName($targetEntity));
|
||||
}
|
||||
public function joinKeyColumnName($entityName, $referencedColumnName = null)
|
||||
public function joinKeyColumnName(string $entityName, ?string $referencedColumnName): string
|
||||
{
|
||||
return strtolower($this->classToTableName($entityName) . '_' .
|
||||
($referencedColumnName ?: $this->referenceColumnName()));
|
||||
|
||||
@@ -465,477 +465,3 @@ above would result in partial objects if any objects in the result
|
||||
are actually a subtype of User. When using DQL, Doctrine
|
||||
automatically includes the necessary joins for this mapping
|
||||
strategy but with native SQL it is your responsibility.
|
||||
|
||||
Named Native Query
|
||||
------------------
|
||||
|
||||
.. note::
|
||||
|
||||
Named Native Queries are deprecated as of version 2.9 and will be removed in ORM 3.0
|
||||
|
||||
You can also map a native query using a named native query mapping.
|
||||
|
||||
To achieve that, you must describe the SQL resultset structure
|
||||
using named native query (and sql resultset mappings if is a several resultset mappings).
|
||||
|
||||
Like named query, a named native query can be defined at class level or in a XML or YAML file.
|
||||
|
||||
|
||||
A resultSetMapping parameter is defined in @NamedNativeQuery,
|
||||
it represents the name of a defined @SqlResultSetMapping.
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace MyProject\Model;
|
||||
/**
|
||||
* @NamedNativeQueries({
|
||||
* @NamedNativeQuery(
|
||||
* name = "fetchMultipleJoinsEntityResults",
|
||||
* resultSetMapping= "mappingMultipleJoinsEntityResults",
|
||||
* query = "SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM users u INNER JOIN addresses a ON u.id = a.user_id INNER JOIN phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username"
|
||||
* ),
|
||||
* })
|
||||
* @SqlResultSetMappings({
|
||||
* @SqlResultSetMapping(
|
||||
* name = "mappingMultipleJoinsEntityResults",
|
||||
* entities= {
|
||||
* @EntityResult(
|
||||
* entityClass = "__CLASS__",
|
||||
* fields = {
|
||||
* @FieldResult(name = "id", column="u_id"),
|
||||
* @FieldResult(name = "name", column="u_name"),
|
||||
* @FieldResult(name = "status", column="u_status"),
|
||||
* }
|
||||
* ),
|
||||
* @EntityResult(
|
||||
* entityClass = "Address",
|
||||
* fields = {
|
||||
* @FieldResult(name = "id", column="a_id"),
|
||||
* @FieldResult(name = "zip", column="a_zip"),
|
||||
* @FieldResult(name = "country", column="a_country"),
|
||||
* }
|
||||
* )
|
||||
* },
|
||||
* columns = {
|
||||
* @ColumnResult("numphones")
|
||||
* }
|
||||
* )
|
||||
*})
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @Column(type="string", length=50, nullable=true) */
|
||||
public $status;
|
||||
|
||||
/** @Column(type="string", length=255, unique=true) */
|
||||
public $username;
|
||||
|
||||
/** @Column(type="string", length=255) */
|
||||
public $name;
|
||||
|
||||
/** @OneToMany(targetEntity="Phonenumber") */
|
||||
public $phonenumbers;
|
||||
|
||||
/** @OneToOne(targetEntity="Address") */
|
||||
public $address;
|
||||
|
||||
// ....
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
<entity name="MyProject\Model\User">
|
||||
<named-native-queries>
|
||||
<named-native-query name="fetchMultipleJoinsEntityResults" result-set-mapping="mappingMultipleJoinsEntityResults">
|
||||
<query>SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM users u INNER JOIN addresses a ON u.id = a.user_id INNER JOIN phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username</query>
|
||||
</named-native-query>
|
||||
</named-native-queries>
|
||||
<sql-result-set-mappings>
|
||||
<sql-result-set-mapping name="mappingMultipleJoinsEntityResults">
|
||||
<entity-result entity-class="__CLASS__">
|
||||
<field-result name="id" column="u_id"/>
|
||||
<field-result name="name" column="u_name"/>
|
||||
<field-result name="status" column="u_status"/>
|
||||
</entity-result>
|
||||
<entity-result entity-class="Address">
|
||||
<field-result name="id" column="a_id"/>
|
||||
<field-result name="zip" column="a_zip"/>
|
||||
<field-result name="country" column="a_country"/>
|
||||
</entity-result>
|
||||
<column-result name="numphones"/>
|
||||
</sql-result-set-mapping>
|
||||
</sql-result-set-mappings>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
MyProject\Model\User:
|
||||
type: entity
|
||||
namedNativeQueries:
|
||||
fetchMultipleJoinsEntityResults:
|
||||
name: fetchMultipleJoinsEntityResults
|
||||
resultSetMapping: mappingMultipleJoinsEntityResults
|
||||
query: SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM users u INNER JOIN addresses a ON u.id = a.user_id INNER JOIN phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username
|
||||
sqlResultSetMappings:
|
||||
mappingMultipleJoinsEntityResults:
|
||||
name: mappingMultipleJoinsEntityResults
|
||||
columnResult:
|
||||
0:
|
||||
name: numphones
|
||||
entityResult:
|
||||
0:
|
||||
entityClass: __CLASS__
|
||||
fieldResult:
|
||||
0:
|
||||
name: id
|
||||
column: u_id
|
||||
1:
|
||||
name: name
|
||||
column: u_name
|
||||
2:
|
||||
name: status
|
||||
column: u_status
|
||||
1:
|
||||
entityClass: Address
|
||||
fieldResult:
|
||||
0:
|
||||
name: id
|
||||
column: a_id
|
||||
1:
|
||||
name: zip
|
||||
column: a_zip
|
||||
2:
|
||||
name: country
|
||||
column: a_country
|
||||
|
||||
|
||||
Things to note:
|
||||
- The resultset mapping declares the entities retrieved by this native query.
|
||||
- Each field of the entity is bound to a SQL alias (or column name).
|
||||
- All fields of the entity including the ones of subclasses
|
||||
and the foreign key columns of related entities have to be present in the SQL query.
|
||||
- Field definitions are optional provided that they map to the same
|
||||
column name as the one declared on the class property.
|
||||
- ``__CLASS__`` is an alias for the mapped class
|
||||
|
||||
|
||||
In the above example,
|
||||
the ``fetchJoinedAddress`` named query use the joinMapping result set mapping.
|
||||
This mapping returns 2 entities, User and Address, each property is declared and associated to a column name,
|
||||
actually the column name retrieved by the query.
|
||||
|
||||
Let's now see an implicit declaration of the property / column.
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace MyProject\Model;
|
||||
/**
|
||||
* @NamedNativeQueries({
|
||||
* @NamedNativeQuery(
|
||||
* name = "findAll",
|
||||
* resultSetMapping = "mappingFindAll",
|
||||
* query = "SELECT * FROM addresses"
|
||||
* ),
|
||||
* })
|
||||
* @SqlResultSetMappings({
|
||||
* @SqlResultSetMapping(
|
||||
* name = "mappingFindAll",
|
||||
* entities= {
|
||||
* @EntityResult(
|
||||
* entityClass = "Address"
|
||||
* )
|
||||
* }
|
||||
* )
|
||||
* })
|
||||
*/
|
||||
class Address
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @Column() */
|
||||
public $country;
|
||||
|
||||
/** @Column() */
|
||||
public $zip;
|
||||
|
||||
/** @Column()*/
|
||||
public $city;
|
||||
|
||||
// ....
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
<entity name="MyProject\Model\Address">
|
||||
<named-native-queries>
|
||||
<named-native-query name="findAll" result-set-mapping="mappingFindAll">
|
||||
<query>SELECT * FROM addresses</query>
|
||||
</named-native-query>
|
||||
</named-native-queries>
|
||||
<sql-result-set-mappings>
|
||||
<sql-result-set-mapping name="mappingFindAll">
|
||||
<entity-result entity-class="Address"/>
|
||||
</sql-result-set-mapping>
|
||||
</sql-result-set-mappings>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
MyProject\Model\Address:
|
||||
type: entity
|
||||
namedNativeQueries:
|
||||
findAll:
|
||||
resultSetMapping: mappingFindAll
|
||||
query: SELECT * FROM addresses
|
||||
sqlResultSetMappings:
|
||||
mappingFindAll:
|
||||
name: mappingFindAll
|
||||
entityResult:
|
||||
address:
|
||||
entityClass: Address
|
||||
|
||||
|
||||
In this example, we only describe the entity member of the result set mapping.
|
||||
The property / column mappings is done using the entity mapping values.
|
||||
In this case the model property is bound to the model_txt column.
|
||||
If the association to a related entity involve a composite primary key,
|
||||
a @FieldResult element should be used for each foreign key column.
|
||||
The @FieldResult name is composed of the property name for the relationship,
|
||||
followed by a dot ("."), followed by the name or the field or property of the primary key.
|
||||
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace MyProject\Model;
|
||||
/**
|
||||
* @NamedNativeQueries({
|
||||
* @NamedNativeQuery(
|
||||
* name = "fetchJoinedAddress",
|
||||
* resultSetMapping= "mappingJoinedAddress",
|
||||
* query = "SELECT u.id, u.name, u.status, a.id AS a_id, a.country AS a_country, a.zip AS a_zip, a.city AS a_city FROM users u INNER JOIN addresses a ON u.id = a.user_id WHERE u.username = ?"
|
||||
* ),
|
||||
* })
|
||||
* @SqlResultSetMappings({
|
||||
* @SqlResultSetMapping(
|
||||
* name = "mappingJoinedAddress",
|
||||
* entities= {
|
||||
* @EntityResult(
|
||||
* entityClass = "__CLASS__",
|
||||
* fields = {
|
||||
* @FieldResult(name = "id"),
|
||||
* @FieldResult(name = "name"),
|
||||
* @FieldResult(name = "status"),
|
||||
* @FieldResult(name = "address.id", column = "a_id"),
|
||||
* @FieldResult(name = "address.zip", column = "a_zip"),
|
||||
* @FieldResult(name = "address.city", column = "a_city"),
|
||||
* @FieldResult(name = "address.country", column = "a_country"),
|
||||
* }
|
||||
* )
|
||||
* }
|
||||
* )
|
||||
* })
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
public $id;
|
||||
|
||||
/** @Column(type="string", length=50, nullable=true) */
|
||||
public $status;
|
||||
|
||||
/** @Column(type="string", length=255, unique=true) */
|
||||
public $username;
|
||||
|
||||
/** @Column(type="string", length=255) */
|
||||
public $name;
|
||||
|
||||
/** @OneToOne(targetEntity="Address") */
|
||||
public $address;
|
||||
|
||||
// ....
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
<entity name="MyProject\Model\User">
|
||||
<named-native-queries>
|
||||
<named-native-query name="fetchJoinedAddress" result-set-mapping="mappingJoinedAddress">
|
||||
<query>SELECT u.id, u.name, u.status, a.id AS a_id, a.country AS a_country, a.zip AS a_zip, a.city AS a_city FROM users u INNER JOIN addresses a ON u.id = a.user_id WHERE u.username = ?</query>
|
||||
</named-native-query>
|
||||
</named-native-queries>
|
||||
<sql-result-set-mappings>
|
||||
<sql-result-set-mapping name="mappingJoinedAddress">
|
||||
<entity-result entity-class="__CLASS__">
|
||||
<field-result name="id"/>
|
||||
<field-result name="name"/>
|
||||
<field-result name="status"/>
|
||||
<field-result name="address.id" column="a_id"/>
|
||||
<field-result name="address.zip" column="a_zip"/>
|
||||
<field-result name="address.city" column="a_city"/>
|
||||
<field-result name="address.country" column="a_country"/>
|
||||
</entity-result>
|
||||
</sql-result-set-mapping>
|
||||
</sql-result-set-mappings>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
MyProject\Model\User:
|
||||
type: entity
|
||||
namedNativeQueries:
|
||||
fetchJoinedAddress:
|
||||
name: fetchJoinedAddress
|
||||
resultSetMapping: mappingJoinedAddress
|
||||
query: SELECT u.id, u.name, u.status, a.id AS a_id, a.country AS a_country, a.zip AS a_zip, a.city AS a_city FROM users u INNER JOIN addresses a ON u.id = a.user_id WHERE u.username = ?
|
||||
sqlResultSetMappings:
|
||||
mappingJoinedAddress:
|
||||
entityResult:
|
||||
0:
|
||||
entityClass: __CLASS__
|
||||
fieldResult:
|
||||
0:
|
||||
name: id
|
||||
1:
|
||||
name: name
|
||||
2:
|
||||
name: status
|
||||
3:
|
||||
name: address.id
|
||||
column: a_id
|
||||
4:
|
||||
name: address.zip
|
||||
column: a_zip
|
||||
5:
|
||||
name: address.city
|
||||
column: a_city
|
||||
6:
|
||||
name: address.country
|
||||
column: a_country
|
||||
|
||||
|
||||
|
||||
If you retrieve a single entity and if you use the default mapping,
|
||||
you can use the resultClass attribute instead of resultSetMapping:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace MyProject\Model;
|
||||
/**
|
||||
* @NamedNativeQueries({
|
||||
* @NamedNativeQuery(
|
||||
* name = "find-by-id",
|
||||
* resultClass = "Address",
|
||||
* query = "SELECT * FROM addresses"
|
||||
* ),
|
||||
* })
|
||||
*/
|
||||
class Address
|
||||
{
|
||||
// ....
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
<entity name="MyProject\Model\Address">
|
||||
<named-native-queries>
|
||||
<named-native-query name="find-by-id" result-class="Address">
|
||||
<query>SELECT * FROM addresses WHERE id = ?</query>
|
||||
</named-native-query>
|
||||
</named-native-queries>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
MyProject\Model\Address:
|
||||
type: entity
|
||||
namedNativeQueries:
|
||||
findAll:
|
||||
name: findAll
|
||||
resultClass: Address
|
||||
query: SELECT * FROM addresses
|
||||
|
||||
|
||||
In some of your native queries, you'll have to return scalar values,
|
||||
for example when building report queries.
|
||||
You can map them in the @SqlResultsetMapping through @ColumnResult.
|
||||
You actually can even mix, entities and scalar returns in the same native query (this is probably not that common though).
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace MyProject\Model;
|
||||
/**
|
||||
* @NamedNativeQueries({
|
||||
* @NamedNativeQuery(
|
||||
* name = "count",
|
||||
* resultSetMapping= "mappingCount",
|
||||
* query = "SELECT COUNT(*) AS count FROM addresses"
|
||||
* )
|
||||
* })
|
||||
* @SqlResultSetMappings({
|
||||
* @SqlResultSetMapping(
|
||||
* name = "mappingCount",
|
||||
* columns = {
|
||||
* @ColumnResult(
|
||||
* name = "count"
|
||||
* )
|
||||
* }
|
||||
* )
|
||||
* })
|
||||
*/
|
||||
class Address
|
||||
{
|
||||
// ....
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
<entity name="MyProject\Model\Address">
|
||||
<named-native-query name="count" result-set-mapping="mappingCount">
|
||||
<query>SELECT COUNT(*) AS count FROM addresses</query>
|
||||
</named-native-query>
|
||||
<sql-result-set-mappings>
|
||||
<sql-result-set-mapping name="mappingCount">
|
||||
<column-result name="count"/>
|
||||
</sql-result-set-mapping>
|
||||
</sql-result-set-mappings>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
MyProject\Model\Address:
|
||||
type: entity
|
||||
namedNativeQueries:
|
||||
count:
|
||||
name: count
|
||||
resultSetMapping: mappingCount
|
||||
query: SELECT COUNT(*) AS count FROM addresses
|
||||
sqlResultSetMappings:
|
||||
mappingCount:
|
||||
name: mappingCount
|
||||
columnResult:
|
||||
count:
|
||||
name: count
|
||||
|
||||
15
docs/en/reference/partial-hydration.rst
Normal file
15
docs/en/reference/partial-hydration.rst
Normal file
@@ -0,0 +1,15 @@
|
||||
Partial Hydration
|
||||
=================
|
||||
|
||||
Partial hydration of entities is allowed in the array hydrator, when
|
||||
only a subset of the fields of an entity are loaded from the database
|
||||
and the nested results are still created based on the entity relationship structure.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$users = $em->createQuery("SELECT PARTIAL u.{id,name}, partial a.{id,street} FROM MyApp\Domain\User u JOIN u.addresses a")
|
||||
->getArrayResult();
|
||||
|
||||
This is a useful optimization when you are not interested in all fields of an entity
|
||||
for performance reasons, for example in use-cases for exporting or rendering lots of data.
|
||||
@@ -1,19 +1,11 @@
|
||||
Partial Objects
|
||||
===============
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Creating Partial Objects through DQL is deprecated and
|
||||
will be removed in the future, use data transfer object
|
||||
support in DQL instead. (\ `Details
|
||||
<https://github.com/doctrine/orm/issues/8471>`_)
|
||||
|
||||
A partial object is an object whose state is not fully initialized
|
||||
after being reconstituted from the database and that is
|
||||
disconnected from the rest of its data. The following section will
|
||||
describe why partial objects are problematic and what the approach
|
||||
of Doctrine2 to this problem is.
|
||||
of Doctrine to this problem is.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -94,5 +86,3 @@ When should I force partial objects?
|
||||
Mainly for optimization purposes, but be careful of premature
|
||||
optimization as partial objects lead to potentially more fragile
|
||||
code.
|
||||
|
||||
|
||||
|
||||
@@ -1,97 +1,20 @@
|
||||
PHP Mapping
|
||||
===========
|
||||
|
||||
Doctrine ORM also allows you to provide the ORM metadata in the form
|
||||
of plain PHP code using the ``ClassMetadata`` API. You can write
|
||||
the code in PHP files or inside of a static function named
|
||||
``loadMetadata($class)`` on the entity class itself.
|
||||
|
||||
PHP Files
|
||||
---------
|
||||
|
||||
.. note::
|
||||
|
||||
PHPDriver is deprecated and will be removed in 3.0, use StaticPHPDriver
|
||||
instead.
|
||||
|
||||
If you wish to write your mapping information inside PHP files that
|
||||
are named after the entity and included to populate the metadata
|
||||
for an entity you can do so by using the ``PHPDriver``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$driver = new PHPDriver('/path/to/php/mapping/files');
|
||||
$em->getConfiguration()->setMetadataDriverImpl($driver);
|
||||
|
||||
Now imagine we had an entity named ``Entities\User`` and we wanted
|
||||
to write a mapping file for it using the above configured
|
||||
``PHPDriver`` instance:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace Entities;
|
||||
|
||||
class User
|
||||
{
|
||||
private $id;
|
||||
private $username;
|
||||
}
|
||||
|
||||
To write the mapping information you just need to create a file
|
||||
named ``Entities.User.php`` inside of the
|
||||
``/path/to/php/mapping/files`` folder:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// /path/to/php/mapping/files/Entities.User.php
|
||||
|
||||
$metadata->mapField(array(
|
||||
'id' => true,
|
||||
'fieldName' => 'id',
|
||||
'type' => 'integer'
|
||||
));
|
||||
|
||||
$metadata->mapField(array(
|
||||
'fieldName' => 'username',
|
||||
'type' => 'string',
|
||||
'options' => array(
|
||||
'fixed' => true,
|
||||
'comment' => "User's login name"
|
||||
)
|
||||
));
|
||||
|
||||
$metadata->mapField(array(
|
||||
'fieldName' => 'login_count',
|
||||
'type' => 'integer',
|
||||
'nullable' => false,
|
||||
'options' => array(
|
||||
'unsigned' => true,
|
||||
'default' => 0
|
||||
)
|
||||
));
|
||||
|
||||
Now we can easily retrieve the populated ``ClassMetadata`` instance
|
||||
where the ``PHPDriver`` includes the file and the
|
||||
``ClassMetadataFactory`` caches it for later retrieval:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$class = $em->getClassMetadata('Entities\User');
|
||||
// or
|
||||
$class = $em->getMetadataFactory()->getMetadataFor('Entities\User');
|
||||
Doctrine ORM also allows you to provide the ORM metadata in the form of plain
|
||||
PHP code using the ``ClassMetadata`` API. You can write the code in inside of a
|
||||
static function named ``loadMetadata($class)`` on the entity class itself.
|
||||
|
||||
Static Function
|
||||
---------------
|
||||
|
||||
In addition to the PHP files you can also specify your mapping
|
||||
information inside of a static function defined on the entity class
|
||||
itself. This is useful for cases where you want to keep your entity
|
||||
and mapping information together but don't want to use attributes or
|
||||
annotations. For this you just need to use the ``StaticPHPDriver``:
|
||||
In addition to other drivers using configuration languages you can also
|
||||
programatically specify your mapping information inside of a static function
|
||||
defined on the entity class itself.
|
||||
|
||||
This is useful for cases where you want to keep your entity and mapping
|
||||
information together but don't want to use attributes. For this you just
|
||||
need to use the ``StaticPHPDriver``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -164,13 +87,11 @@ The API of the ClassMetadataBuilder has the following methods with a fluent inte
|
||||
- ``setTable($name)``
|
||||
- ``addIndex(array $columns, $indexName)``
|
||||
- ``addUniqueConstraint(array $columns, $constraintName)``
|
||||
- ``addNamedQuery($name, $dqlQuery)``
|
||||
- ``setJoinedTableInheritance()``
|
||||
- ``setSingleTableInheritance()``
|
||||
- ``setDiscriminatorColumn($name, $type = 'string', $length = 255, $columnDefinition = null, $enumType = null, $options = [])``
|
||||
- ``addDiscriminatorMapClass($name, $class)``
|
||||
- ``setChangeTrackingPolicyDeferredExplicit()``
|
||||
- ``setChangeTrackingPolicyNotify()``
|
||||
- ``addLifecycleEvent($methodName, $event)``
|
||||
- ``addManyToOne($name, $targetEntity, $inversedBy = null)``
|
||||
- ``addInverseOneToOne($name, $targetEntity, $mappedBy)``
|
||||
@@ -272,7 +193,6 @@ Inheritance Getters
|
||||
- ``isInheritanceTypeNone()``
|
||||
- ``isInheritanceTypeJoined()``
|
||||
- ``isInheritanceTypeSingleTable()``
|
||||
- ``isInheritanceTypeTablePerClass()``
|
||||
- ``isInheritedField($fieldName)``
|
||||
- ``isInheritedAssociation($fieldName)``
|
||||
|
||||
@@ -282,7 +202,6 @@ Change Tracking Getters
|
||||
|
||||
- ``isChangeTrackingDeferredExplicit()``
|
||||
- ``isChangeTrackingDeferredImplicit()``
|
||||
- ``isChangeTrackingNotify()``
|
||||
|
||||
Field & Association Getters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -290,6 +209,7 @@ Field & Association Getters
|
||||
|
||||
- ``isUniqueField($fieldName)``
|
||||
- ``isNullable($fieldName)``
|
||||
- ``isIndexed($fieldName)``
|
||||
- ``getColumnName($fieldName)``
|
||||
- ``getFieldMapping($fieldName)``
|
||||
- ``getAssociationMapping($fieldName)``
|
||||
|
||||
@@ -611,3 +611,21 @@ same query of example 6 written using
|
||||
->add('from', new Expr\From('User', 'u'))
|
||||
->add('where', new Expr\Comparison('u.id', '=', '?1'))
|
||||
->add('orderBy', new Expr\OrderBy('u.name', 'ASC'));
|
||||
|
||||
Binding Parameters to Placeholders
|
||||
----------------------------------
|
||||
|
||||
It is often not necessary to know about the exact placeholder names when
|
||||
building a query. You can use a helper method to bind a value to a placeholder
|
||||
and directly use that placeholder in your query as a return value:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// $qb instanceof QueryBuilder
|
||||
|
||||
$qb->select('u')
|
||||
->from('User', 'u')
|
||||
->where('u.email = ' . $qb->createNamedParameter($userInputEmail))
|
||||
;
|
||||
// SELECT u FROM User u WHERE email = :dcValue1
|
||||
|
||||
@@ -295,35 +295,11 @@ level cache region.
|
||||
// other properties and methods
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @Entity
|
||||
* @Cache("NONSTRICT_READ_WRITE")
|
||||
*/
|
||||
class State
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
*/
|
||||
protected int|null $id = null;
|
||||
|
||||
/**
|
||||
* @Column(unique=true)
|
||||
*/
|
||||
protected string $name;
|
||||
|
||||
// other properties and methods
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="Country">
|
||||
@@ -335,24 +311,6 @@ level cache region.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Country:
|
||||
type: entity
|
||||
cache:
|
||||
usage: READ_ONLY
|
||||
region: my_entity_region
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
id: true
|
||||
generator:
|
||||
strategy: IDENTITY
|
||||
fields:
|
||||
name:
|
||||
type: string
|
||||
|
||||
|
||||
Association cache definition
|
||||
----------------------------
|
||||
The most common use case is to cache entities. But we can also cache relationships.
|
||||
@@ -389,49 +347,11 @@ It caches the primary keys of association and cache each element will be cached
|
||||
// other properties and methods
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @Entity
|
||||
* @Cache("NONSTRICT_READ_WRITE")
|
||||
*/
|
||||
class State
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
* @GeneratedValue
|
||||
* @Column(type="integer")
|
||||
*/
|
||||
protected int|null $id = null;
|
||||
|
||||
/**
|
||||
* @Column(unique=true)
|
||||
*/
|
||||
protected string $name;
|
||||
|
||||
/**
|
||||
* @Cache("NONSTRICT_READ_WRITE")
|
||||
* @ManyToOne(targetEntity="Country")
|
||||
* @JoinColumn(name="country_id", referencedColumnName="id")
|
||||
*/
|
||||
protected Country|null $country;
|
||||
|
||||
/**
|
||||
* @Cache("NONSTRICT_READ_WRITE")
|
||||
* @OneToMany(targetEntity="City", mappedBy="state")
|
||||
* @var Collection<int, City>
|
||||
*/
|
||||
protected Collection $cities;
|
||||
|
||||
// other properties and methods
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="State">
|
||||
@@ -458,38 +378,6 @@ It caches the primary keys of association and cache each element will be cached
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
State:
|
||||
type: entity
|
||||
cache:
|
||||
usage: NONSTRICT_READ_WRITE
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
id: true
|
||||
generator:
|
||||
strategy: IDENTITY
|
||||
fields:
|
||||
name:
|
||||
type: string
|
||||
|
||||
manyToOne:
|
||||
state:
|
||||
targetEntity: Country
|
||||
joinColumns:
|
||||
country_id:
|
||||
referencedColumnName: id
|
||||
cache:
|
||||
usage: NONSTRICT_READ_WRITE
|
||||
|
||||
oneToMany:
|
||||
cities:
|
||||
targetEntity:City
|
||||
mappedBy: state
|
||||
cache:
|
||||
usage: NONSTRICT_READ_WRITE
|
||||
|
||||
.. note::
|
||||
|
||||
for this to work, the target entity must also be marked as cacheable.
|
||||
|
||||
@@ -83,18 +83,8 @@ The following Commands are currently available:
|
||||
cache drivers.
|
||||
- ``orm:clear-cache:result`` Clear result cache of the various
|
||||
cache drivers.
|
||||
- ``orm:convert-d1-schema`` Converts Doctrine 1.X schema into a
|
||||
Doctrine 2.X schema.
|
||||
- ``orm:convert-mapping`` Convert mapping information between
|
||||
supported formats.
|
||||
- ``orm:ensure-production-settings`` Verify that Doctrine is
|
||||
properly configured for a production environment.
|
||||
- ``orm:generate-entities`` Generate entity classes and method
|
||||
stubs from your mapping information.
|
||||
- ``orm:generate-proxies`` Generates proxy classes for entity
|
||||
classes.
|
||||
- ``orm:generate-repositories`` Generate repository classes from
|
||||
your mapping information.
|
||||
classes. Deprecated in favor of using native lazy objects.
|
||||
- ``orm:run-dql`` Executes arbitrary DQL directly from the command
|
||||
line.
|
||||
- ``orm:schema-tool:create`` Processes the schema and either
|
||||
@@ -107,14 +97,10 @@ The following Commands are currently available:
|
||||
update the database schema of EntityManager Storage Connection or
|
||||
generate the SQL output.
|
||||
|
||||
For these commands are also available aliases:
|
||||
The following alias is defined:
|
||||
|
||||
|
||||
- ``orm:convert:d1-schema`` is alias for ``orm:convert-d1-schema``.
|
||||
- ``orm:convert:mapping`` is alias for ``orm:convert-mapping``.
|
||||
- ``orm:generate:entities`` is alias for ``orm:generate-entities``.
|
||||
- ``orm:generate:proxies`` is alias for ``orm:generate-proxies``.
|
||||
- ``orm:generate:repositories`` is alias for ``orm:generate-repositories``.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -225,163 +211,6 @@ will output the SQL for the ran operation.
|
||||
|
||||
$ php bin/doctrine orm:schema-tool:create --dump-sql
|
||||
|
||||
Entity Generation
|
||||
-----------------
|
||||
|
||||
Generate entity classes and method stubs from your mapping information.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php bin/doctrine orm:generate-entities
|
||||
$ php bin/doctrine orm:generate-entities --update-entities
|
||||
$ php bin/doctrine orm:generate-entities --regenerate-entities
|
||||
|
||||
This command is not suited for constant usage. It is a little helper and does
|
||||
not support all the mapping edge cases very well. You still have to put work
|
||||
in your entities after using this command.
|
||||
|
||||
It is possible to use the EntityGenerator on code that you have already written. It will
|
||||
not be lost. The EntityGenerator will only append new code to your
|
||||
file and will not delete the old code. However this approach may still be prone
|
||||
to error and we suggest you use code repositories such as GIT or SVN to make
|
||||
backups of your code.
|
||||
|
||||
It makes sense to generate the entity code if you are using entities as Data
|
||||
Access Objects only and don't put much additional logic on them. If you are
|
||||
however putting much more logic on the entities you should refrain from using
|
||||
the entity-generator and code your entities manually.
|
||||
|
||||
.. note::
|
||||
|
||||
Even if you specified Inheritance options in your
|
||||
XML or YAML Mapping files the generator cannot generate the base and
|
||||
child classes for you correctly, because it doesn't know which
|
||||
class is supposed to extend which. You have to adjust the entity
|
||||
code manually for inheritance to work!
|
||||
|
||||
|
||||
Convert Mapping Information
|
||||
---------------------------
|
||||
|
||||
Convert mapping information between supported formats.
|
||||
|
||||
This is an **execute one-time** command. It should not be necessary for
|
||||
you to call this method multiple times, especially when using the ``--from-database``
|
||||
flag.
|
||||
|
||||
Converting an existing database schema into mapping files only solves about 70-80%
|
||||
of the necessary mapping information. Additionally the detection from an existing
|
||||
database cannot detect inverse associations, inheritance types,
|
||||
entities with foreign keys as primary keys and many of the
|
||||
semantical operations on associations such as cascade.
|
||||
|
||||
.. note::
|
||||
|
||||
There is no need to convert YAML or XML mapping files to annotations
|
||||
every time you make changes. All mapping drivers are first class citizens
|
||||
in Doctrine 2 and can be used as runtime mapping for the ORM. See the
|
||||
docs on XML and YAML Mapping for an example how to register this metadata
|
||||
drivers as primary mapping source.
|
||||
|
||||
To convert some mapping information between the various supported
|
||||
formats you can use the ``ClassMetadataExporter`` to get exporter
|
||||
instances for the different formats:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cme = new \Doctrine\ORM\Tools\Export\ClassMetadataExporter();
|
||||
|
||||
Once you have a instance you can use it to get an exporter. For
|
||||
example, the yml exporter:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$exporter = $cme->getExporter('yml', '/path/to/export/yml');
|
||||
|
||||
Now you can export some ``ClassMetadata`` instances:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$classes = array(
|
||||
$em->getClassMetadata('Entities\User'),
|
||||
$em->getClassMetadata('Entities\Profile')
|
||||
);
|
||||
$exporter->setMetadata($classes);
|
||||
$exporter->export();
|
||||
|
||||
This functionality is also available from the command line to
|
||||
convert your loaded mapping information to another format. The
|
||||
``orm:convert-mapping`` command accepts two arguments, the type to
|
||||
convert to and the path to generate it:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php bin/doctrine orm:convert-mapping xml /path/to/mapping-path-converted-to-xml
|
||||
|
||||
Reverse Engineering
|
||||
-------------------
|
||||
|
||||
You can use the ``DatabaseDriver`` to reverse engineer a database to an
|
||||
array of ``ClassMetadata`` instances and generate YAML, XML, etc. from
|
||||
them.
|
||||
|
||||
.. note::
|
||||
|
||||
Reverse Engineering is a **one-time** process that can get you started with a project.
|
||||
Converting an existing database schema into mapping files only detects about 70-80%
|
||||
of the necessary mapping information. Additionally the detection from an existing
|
||||
database cannot detect inverse associations, inheritance types,
|
||||
entities with foreign keys as primary keys and many of the
|
||||
semantical operations on associations such as cascade.
|
||||
|
||||
First you need to retrieve the metadata instances with the
|
||||
``DatabaseDriver``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$em->getConfiguration()->setMetadataDriverImpl(
|
||||
new \Doctrine\ORM\Mapping\Driver\DatabaseDriver(
|
||||
$em->getConnection()->getSchemaManager()
|
||||
)
|
||||
);
|
||||
|
||||
$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory();
|
||||
$cmf->setEntityManager($em);
|
||||
$metadata = $cmf->getAllMetadata();
|
||||
|
||||
Now you can get an exporter instance and export the loaded metadata
|
||||
to yml:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cme = new \Doctrine\ORM\Tools\Export\ClassMetadataExporter();
|
||||
$exporter = $cme->getExporter('yml', '/path/to/export/yml');
|
||||
$exporter->setMetadata($metadata);
|
||||
$exporter->export();
|
||||
|
||||
You can also reverse engineer a database using the
|
||||
``orm:convert-mapping`` command:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php bin/doctrine orm:convert-mapping --from-database yml /path/to/mapping-path-converted-to-yml
|
||||
|
||||
.. note::
|
||||
|
||||
Reverse Engineering is not always working perfectly
|
||||
depending on special cases. It will only detect Many-To-One
|
||||
relations (even if they are One-To-One) and will try to create
|
||||
entities from Many-To-Many tables. It also has problems with naming
|
||||
of foreign keys that have multiple column names. Any Reverse
|
||||
Engineered Database-Schema needs considerable manual work to become
|
||||
a useful domain model.
|
||||
|
||||
|
||||
Runtime vs Development Mapping Validation
|
||||
-----------------------------------------
|
||||
|
||||
|
||||
@@ -202,17 +202,6 @@ example we'll use an integer.
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
/** @Version @Column(type="integer") */
|
||||
private int $version;
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -221,15 +210,6 @@ example we'll use an integer.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
fields:
|
||||
version:
|
||||
type: integer
|
||||
version: true
|
||||
|
||||
Alternatively a datetime type can be used (which maps to a SQL
|
||||
timestamp or datetime):
|
||||
|
||||
@@ -246,17 +226,6 @@ timestamp or datetime):
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
/** @Version @Column(type="datetime") */
|
||||
private DateTime $version;
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -265,15 +234,6 @@ timestamp or datetime):
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
fields:
|
||||
version:
|
||||
type: datetime
|
||||
version: true
|
||||
|
||||
Version numbers (not timestamps) should however be preferred as
|
||||
they can not potentially conflict in a highly concurrent
|
||||
environment, unlike timestamps where this is a possibility,
|
||||
|
||||
@@ -47,21 +47,6 @@ Then, an entity using the ``CustomIdObject`` typed field will be correctly assig
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="cms_users_typed_with_custom_typed_field")
|
||||
*/
|
||||
class UserTypedWithCustomTypedField
|
||||
{
|
||||
/** @Column */
|
||||
public CustomIdObject $customId;
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -176,4 +161,4 @@ You need to create a class which implements ``Doctrine\ORM\Mapping\TypedFieldMap
|
||||
|
||||
Note that this case checks whether the mapping is already assigned, and if yes, it skips it. This is up to your
|
||||
implementation. You can make a "greedy" mapper which will always override the mapping with its own type, or one
|
||||
that behaves like the ``DefaultTypedFieldMapper`` and does not modify the type once its set prior in the chain.
|
||||
that behaves like the ``DefaultTypedFieldMapper`` and does not modify the type once its set prior in the chain.
|
||||
|
||||
@@ -102,7 +102,7 @@ How Doctrine Detects Changes
|
||||
----------------------------
|
||||
|
||||
Doctrine is a data-mapper that tries to achieve persistence-ignorance (PI).
|
||||
This means you map php objects into a relational database that don't
|
||||
This means you map PHP objects into a relational database that don't
|
||||
necessarily know about the database at all. A natural question would now be,
|
||||
"how does Doctrine even detect objects have changed?".
|
||||
|
||||
@@ -129,16 +129,10 @@ optimize the performance of the Flush Operation:
|
||||
- Temporarily mark entities as read only. If you have a very large UnitOfWork
|
||||
but know that a large set of entities has not changed, just mark them as read
|
||||
only with ``$entityManager->getUnitOfWork()->markReadOnly($entity)``.
|
||||
- Flush only a single entity with ``$entityManager->flush($entity)``.
|
||||
- Use :doc:`Change Tracking Policies <change-tracking-policies>` to use more
|
||||
explicit strategies of notifying the UnitOfWork what objects/properties
|
||||
changed.
|
||||
|
||||
.. note::
|
||||
|
||||
Flush only a single entity with ``$entityManager->flush($entity)`` is deprecated and will be removed in ORM 3.0.
|
||||
(\ `Details <https://github.com/doctrine/orm/issues/8459>`_)
|
||||
|
||||
Query Internals
|
||||
---------------
|
||||
|
||||
|
||||
@@ -415,7 +415,7 @@ Transitive persistence / Cascade Operations
|
||||
Doctrine ORM provides a mechanism for transitive persistence through cascading of certain operations.
|
||||
Each association to another entity or a collection of
|
||||
entities can be configured to automatically cascade the following operations to the associated entities:
|
||||
``persist``, ``remove``, ``merge``, ``detach``, ``refresh`` or ``all``.
|
||||
``persist``, ``remove``, ``detach``, ``refresh`` or ``all``.
|
||||
|
||||
The main use case for ``cascade: persist`` is to avoid "exposing" associated entities to your PHP application.
|
||||
Continuing with the User-Comment example of this chapter, this is how the creation of a new user and a new
|
||||
@@ -736,6 +736,35 @@ methods:
|
||||
|
||||
.. note::
|
||||
|
||||
There is a limitation on the compatibility of Criteria comparisons.
|
||||
You have to use scalar values only as the value in a comparison or
|
||||
the behaviour between different backends is not the same.
|
||||
Depending on whether the collection has already been loaded from the
|
||||
database or not, criteria matching may happen at the database/SQL level
|
||||
or on objects in memory. This may lead to different results and come
|
||||
surprising, for example when a code change in one place leads to a collection
|
||||
becoming initialized and, as a side effect, returning a different result
|
||||
or even breaking a ``matching()`` call somewhere else. Also, collection
|
||||
initialization state in practical use cases may differ from the one covered
|
||||
in unit tests.
|
||||
|
||||
Database level comparisons are based on scalar representations of the values
|
||||
stored in entity properties. The field names passed to expressions correspond
|
||||
to property names. Comparison and sorting may be affected by
|
||||
database-specific behavior. For example, MySQL enum types sort by index position,
|
||||
not lexicographically by value.
|
||||
|
||||
In-memory handling is based on the ``Selectable`` API of `Doctrine Collections <https://www.doctrine-project.org/projects/doctrine-collections/en/stable/index.html#matching>`.
|
||||
In this case, field names passed to expressions are being used to derive accessor
|
||||
method names. Strict type comparisons are used for equal and not-equal checks,
|
||||
and generally PHP language rules are being used for other comparison operators
|
||||
or sorting.
|
||||
|
||||
As a general guidance, for consistent results use the Criteria API with scalar
|
||||
values only. Note that ``DateTime`` and ``DateTimeImmutable`` are two predominant
|
||||
examples of value objects that are *not* scalars.
|
||||
|
||||
Refrain from using special database-level column types or custom Doctrine Types
|
||||
that may lead to database-specific comparison or sorting rules being applied, or
|
||||
to database-level values being different from object field values.
|
||||
|
||||
Provide accessor methods for all entity fields used in criteria expressions,
|
||||
and implement those methods in a way that their return value is the
|
||||
same as the database-level value.
|
||||
|
||||
@@ -166,7 +166,7 @@ your code. See the following code:
|
||||
|
||||
Traversing the object graph for parts that are lazy-loaded will
|
||||
easily trigger lots of SQL queries and will perform badly if used
|
||||
to heavily. Make sure to use DQL to fetch-join all the parts of the
|
||||
too heavily. Make sure to use DQL to fetch-join all the parts of the
|
||||
object-graph that you need as efficiently as possible.
|
||||
|
||||
|
||||
@@ -414,77 +414,6 @@ automatically without invoking the ``detach`` method:
|
||||
The ``detach`` operation is usually not as frequently needed and
|
||||
used as ``persist`` and ``remove``.
|
||||
|
||||
Merging entities
|
||||
----------------
|
||||
|
||||
Merging entities refers to the merging of (usually detached)
|
||||
entities into the context of an EntityManager so that they become
|
||||
managed again. To merge the state of an entity into an
|
||||
EntityManager use the ``EntityManager#merge($entity)`` method. The
|
||||
state of the passed entity will be merged into a managed copy of
|
||||
this entity and this copy will subsequently be returned.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$detachedEntity = unserialize($serializedEntity); // some detached entity
|
||||
$entity = $em->merge($detachedEntity);
|
||||
// $entity now refers to the fully managed copy returned by the merge operation.
|
||||
// The EntityManager $em now manages the persistence of $entity as usual.
|
||||
|
||||
|
||||
The semantics of the merge operation, applied to an entity X, are
|
||||
as follows:
|
||||
|
||||
|
||||
- If X is a detached entity, the state of X is copied onto a
|
||||
pre-existing managed entity instance X' of the same identity.
|
||||
- If X is a new entity instance, a new managed copy X' will be
|
||||
created and the state of X is copied onto this managed instance.
|
||||
- If X is a removed entity instance, an InvalidArgumentException
|
||||
will be thrown.
|
||||
- If X is a managed entity, it is ignored by the merge operation,
|
||||
however, the merge operation is cascaded to entities referenced by
|
||||
relationships from X if these relationships have been mapped with
|
||||
the cascade element value MERGE or ALL (see ":ref:`transitive-persistence`").
|
||||
- For all entities Y referenced by relationships from X having the
|
||||
cascade element value MERGE or ALL, Y is merged recursively as Y'.
|
||||
For all such Y referenced by X, X' is set to reference Y'. (Note
|
||||
that if X is managed then X is the same object as X'.)
|
||||
- If X is an entity merged to X', with a reference to another
|
||||
entity Y, where cascade=MERGE or cascade=ALL is not specified, then
|
||||
navigation of the same association from X' yields a reference to a
|
||||
managed object Y' with the same persistent identity as Y.
|
||||
|
||||
The ``merge`` operation will throw an ``OptimisticLockException``
|
||||
if the entity being merged uses optimistic locking through a
|
||||
version field and the versions of the entity being merged and the
|
||||
managed copy don't match. This usually means that the entity has
|
||||
been modified while being detached.
|
||||
|
||||
The ``merge`` operation is usually not as frequently needed and
|
||||
used as ``persist`` and ``remove``. The most common scenario for
|
||||
the ``merge`` operation is to reattach entities to an EntityManager
|
||||
that come from some cache (and are therefore detached) and you want
|
||||
to modify and persist such an entity.
|
||||
|
||||
.. warning::
|
||||
|
||||
If you need to perform multiple merges of entities that share certain subparts
|
||||
of their object-graphs and cascade merge, then you have to call ``EntityManager#clear()`` between the
|
||||
successive calls to ``EntityManager#merge()``. Otherwise you might end up with
|
||||
multiple copies of the "same" object in the database, however with different ids.
|
||||
|
||||
.. note::
|
||||
|
||||
If you load some detached entities from a cache and you do
|
||||
not need to persist or delete them or otherwise make use of them
|
||||
without the need for persistence services there is no need to use
|
||||
``merge``. I.e. you can simply pass detached objects from a cache
|
||||
directly to the view.
|
||||
|
||||
|
||||
Synchronization with the Database
|
||||
---------------------------------
|
||||
@@ -595,7 +524,7 @@ during development.
|
||||
.. note::
|
||||
|
||||
Do not invoke ``flush`` after every change to an entity
|
||||
or every single invocation of persist/remove/merge/... This is an
|
||||
or every single invocation of persist/remove/... This is an
|
||||
anti-pattern and unnecessarily reduces the performance of your
|
||||
application. Instead, form units of work that operate on your
|
||||
objects and call ``flush`` when you are done. While serving a
|
||||
@@ -863,7 +792,7 @@ By default the EntityManager returns a default implementation of
|
||||
``Doctrine\ORM\EntityRepository`` when you call
|
||||
``EntityManager#getRepository($entityClass)``. You can overwrite
|
||||
this behaviour by specifying the class name of your own Entity
|
||||
Repository in the Attribute, Annotation, XML or YAML metadata. In large
|
||||
Repository in the Attribute or XML metadata. In large
|
||||
applications that require lots of specialized DQL queries using a
|
||||
custom repository is one recommended way of grouping these queries
|
||||
in a central location.
|
||||
|
||||
@@ -2,7 +2,8 @@ XML Mapping
|
||||
===========
|
||||
|
||||
The XML mapping driver enables you to provide the ORM metadata in
|
||||
form of XML documents.
|
||||
form of XML documents. It requires the ``dom`` extension in order to be
|
||||
able to validate your mapping documents against its XML Schema.
|
||||
|
||||
The XML driver is backed by an XML Schema document that describes
|
||||
the structure of a mapping document. The most recent version of the
|
||||
@@ -17,7 +18,7 @@ setup for the latest code in trunk.
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -45,7 +46,7 @@ In order to work, this requires certain conventions:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$driver->setFileExtension('.xml');
|
||||
$driver->getLocator()->setFileExtension('.xml');
|
||||
|
||||
It is recommended to put all XML mapping documents in a single
|
||||
folder but you can spread the documents over several folders if you
|
||||
@@ -103,7 +104,7 @@ of several common elements:
|
||||
// Doctrine.Tests.ORM.Mapping.User.dcm.xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -111,7 +112,6 @@ of several common elements:
|
||||
|
||||
<indexes>
|
||||
<index name="name_idx" columns="name"/>
|
||||
<index columns="user_email"/>
|
||||
</indexes>
|
||||
|
||||
<unique-constraints>
|
||||
@@ -130,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>
|
||||
@@ -254,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.
|
||||
@@ -691,7 +693,6 @@ specified by their respective tags:
|
||||
|
||||
|
||||
- ``<cascade-persist />``
|
||||
- ``<cascade-merge />``
|
||||
- ``<cascade-remove />``
|
||||
- ``<cascade-refresh />``
|
||||
- ``<cascade-detach />``
|
||||
@@ -770,7 +771,7 @@ entity relationship. You can define this in XML with the "association-key" attri
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
YAML Mapping
|
||||
============
|
||||
|
||||
.. warning::
|
||||
The YAML driver is deprecated and will be removed in version 3.0.
|
||||
It is strongly recommended to switch to one of the other mappings.
|
||||
|
||||
The YAML mapping driver enables you to provide the ORM metadata in
|
||||
form of YAML documents.
|
||||
|
||||
The YAML mapping document of a class is loaded on-demand the first
|
||||
time it is requested and subsequently stored in the metadata cache.
|
||||
In order to work, this requires certain conventions:
|
||||
|
||||
|
||||
- Each entity/mapped superclass must get its own dedicated YAML
|
||||
mapping document.
|
||||
- The name of the mapping document must consist of the fully
|
||||
qualified name of the class, where namespace separators are
|
||||
replaced by dots (.).
|
||||
- All mapping documents should get the extension ".dcm.yml" to
|
||||
identify it as a Doctrine mapping file. This is more of a
|
||||
convention and you are not forced to do this. You can change the
|
||||
file extension easily enough.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$driver->setFileExtension('.yml');
|
||||
|
||||
It is recommended to put all YAML mapping documents in a single
|
||||
folder but you can spread the documents over several folders if you
|
||||
want to. In order to tell the YamlDriver where to look for your
|
||||
mapping documents, supply an array of paths as the first argument
|
||||
of the constructor, like this:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Driver\YamlDriver;
|
||||
|
||||
// $config instanceof Doctrine\ORM\Configuration
|
||||
$driver = new YamlDriver(array('/path/to/files'));
|
||||
$config->setMetadataDriverImpl($driver);
|
||||
|
||||
Simplified YAML Driver
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Symfony project sponsored a driver that simplifies usage of the YAML Driver.
|
||||
The changes between the original driver are:
|
||||
|
||||
- File Extension is .orm.yml
|
||||
- Filenames are shortened, "MyProject\\Entities\\User" will become User.orm.yml
|
||||
- You can add a global file and add multiple entities in this file.
|
||||
|
||||
Configuration of this client works a little bit different:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$namespaces = array(
|
||||
'/path/to/files1' => 'MyProject\Entities',
|
||||
'/path/to/files2' => 'OtherProject\Entities'
|
||||
);
|
||||
$driver = new \Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver($namespaces);
|
||||
$driver->setGlobalBasename('global'); // global.orm.yml
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
As a quick start, here is a small example document that makes use
|
||||
of several common elements:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# Doctrine.Tests.ORM.Mapping.User.dcm.yml
|
||||
Doctrine\Tests\ORM\Mapping\User:
|
||||
type: entity
|
||||
repositoryClass: Doctrine\Tests\ORM\Mapping\UserRepository
|
||||
table: cms_users
|
||||
schema: schema_name # The schema the table lies in, for platforms that support schemas (Optional, >= 2.5)
|
||||
readOnly: true
|
||||
indexes:
|
||||
name_index:
|
||||
columns: [ name ]
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
generator:
|
||||
strategy: AUTO
|
||||
fields:
|
||||
name:
|
||||
type: string
|
||||
length: 50
|
||||
email:
|
||||
type: string
|
||||
length: 32
|
||||
column: user_email
|
||||
unique: true
|
||||
options:
|
||||
fixed: true
|
||||
comment: User's email address
|
||||
loginCount:
|
||||
type: integer
|
||||
column: login_count
|
||||
nullable: false
|
||||
options:
|
||||
unsigned: true
|
||||
default: 0
|
||||
oneToOne:
|
||||
address:
|
||||
targetEntity: Address
|
||||
joinColumn:
|
||||
name: address_id
|
||||
referencedColumnName: id
|
||||
onDelete: CASCADE
|
||||
oneToMany:
|
||||
phonenumbers:
|
||||
targetEntity: Phonenumber
|
||||
mappedBy: user
|
||||
cascade: ["persist", "merge"]
|
||||
manyToMany:
|
||||
groups:
|
||||
targetEntity: Group
|
||||
joinTable:
|
||||
name: cms_users_groups
|
||||
joinColumns:
|
||||
user_id:
|
||||
referencedColumnName: id
|
||||
inverseJoinColumns:
|
||||
group_id:
|
||||
referencedColumnName: id
|
||||
lifecycleCallbacks:
|
||||
prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ]
|
||||
postPersist: [ doStuffOnPostPersist ]
|
||||
|
||||
Be aware that class-names specified in the YAML files should be
|
||||
fully qualified.
|
||||
|
||||
Reference
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Unique Constraints
|
||||
------------------
|
||||
|
||||
It is possible to define unique constraints by the following declaration:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# ECommerceProduct.orm.yml
|
||||
ECommerceProduct:
|
||||
type: entity
|
||||
fields:
|
||||
# definition of some fields
|
||||
uniqueConstraints:
|
||||
search_idx:
|
||||
columns: [ name, email ]
|
||||
|
||||
@@ -1,84 +1,76 @@
|
||||
.. toc::
|
||||
:orphan:
|
||||
|
||||
.. tocheader:: Tutorials
|
||||
.. toctree::
|
||||
:caption: Tutorials
|
||||
:depth: 3
|
||||
|
||||
.. toctree::
|
||||
:depth: 3
|
||||
tutorials/getting-started
|
||||
tutorials/getting-started-database
|
||||
tutorials/getting-started-models
|
||||
tutorials/working-with-indexed-associations
|
||||
tutorials/extra-lazy-associations
|
||||
tutorials/composite-primary-keys
|
||||
tutorials/ordered-associations
|
||||
tutorials/override-field-association-mappings-in-subclasses
|
||||
tutorials/pagination
|
||||
tutorials/embeddables
|
||||
|
||||
tutorials/getting-started
|
||||
tutorials/getting-started-database
|
||||
tutorials/getting-started-models
|
||||
tutorials/working-with-indexed-associations
|
||||
tutorials/extra-lazy-associations
|
||||
tutorials/composite-primary-keys
|
||||
tutorials/ordered-associations
|
||||
tutorials/override-field-association-mappings-in-subclasses
|
||||
tutorials/pagination
|
||||
tutorials/embeddables
|
||||
.. toctree::
|
||||
:caption: Reference
|
||||
:depth: 3
|
||||
|
||||
.. toc::
|
||||
reference/architecture
|
||||
reference/configuration
|
||||
reference/faq
|
||||
reference/basic-mapping
|
||||
reference/association-mapping
|
||||
reference/inheritance-mapping
|
||||
reference/working-with-objects
|
||||
reference/working-with-associations
|
||||
reference/typedfieldmapper
|
||||
reference/events
|
||||
reference/unitofwork
|
||||
reference/unitofwork-associations
|
||||
reference/transactions-and-concurrency
|
||||
reference/batch-processing
|
||||
reference/dql-doctrine-query-language
|
||||
reference/query-builder
|
||||
reference/native-sql
|
||||
reference/change-tracking-policies
|
||||
reference/partial-hydration
|
||||
reference/partial-objects
|
||||
reference/attributes-reference
|
||||
reference/xml-mapping
|
||||
reference/php-mapping
|
||||
reference/caching
|
||||
reference/improving-performance
|
||||
reference/tools
|
||||
reference/metadata-drivers
|
||||
reference/best-practices
|
||||
reference/limitations-and-known-issues
|
||||
tutorials/pagination
|
||||
reference/filters
|
||||
reference/namingstrategy
|
||||
reference/advanced-configuration
|
||||
reference/second-level-cache
|
||||
reference/security
|
||||
|
||||
.. tocheader:: Reference
|
||||
.. toctree::
|
||||
:caption: Cookbook
|
||||
:depth: 3
|
||||
|
||||
.. toctree::
|
||||
:depth: 3
|
||||
|
||||
reference/architecture
|
||||
reference/configuration
|
||||
reference/faq
|
||||
reference/basic-mapping
|
||||
reference/association-mapping
|
||||
reference/inheritance-mapping
|
||||
reference/working-with-objects
|
||||
reference/working-with-associations
|
||||
reference/typedfieldmapper
|
||||
reference/events
|
||||
reference/unitofwork
|
||||
reference/unitofwork-associations
|
||||
reference/transactions-and-concurrency
|
||||
reference/batch-processing
|
||||
reference/dql-doctrine-query-language
|
||||
reference/query-builder
|
||||
reference/native-sql
|
||||
reference/change-tracking-policies
|
||||
reference/partial-objects
|
||||
reference/annotations-reference
|
||||
reference/attributes-reference
|
||||
reference/xml-mapping
|
||||
reference/yaml-mapping
|
||||
reference/php-mapping
|
||||
reference/caching
|
||||
reference/improving-performance
|
||||
reference/tools
|
||||
reference/metadata-drivers
|
||||
reference/best-practices
|
||||
reference/limitations-and-known-issues
|
||||
tutorials/pagination
|
||||
reference/filters
|
||||
reference/namingstrategy
|
||||
reference/advanced-configuration
|
||||
reference/second-level-cache
|
||||
reference/security
|
||||
|
||||
.. toc::
|
||||
|
||||
.. tocheader:: Cookbook
|
||||
|
||||
.. toctree::
|
||||
:depth: 3
|
||||
|
||||
cookbook/aggregate-fields
|
||||
cookbook/custom-mapping-types
|
||||
cookbook/decorator-pattern
|
||||
cookbook/dql-custom-walkers
|
||||
cookbook/dql-user-defined-functions
|
||||
cookbook/implementing-arrayaccess-for-domain-objects
|
||||
cookbook/implementing-the-notify-changetracking-policy
|
||||
cookbook/resolve-target-entity-listener
|
||||
cookbook/sql-table-prefixes
|
||||
cookbook/strategy-cookbook-introduction
|
||||
cookbook/validation-of-entities
|
||||
cookbook/working-with-datetime
|
||||
cookbook/mysql-enums
|
||||
cookbook/advanced-field-value-conversion-using-custom-mapping-types
|
||||
cookbook/entities-in-session
|
||||
cookbook/aggregate-fields
|
||||
cookbook/custom-mapping-types
|
||||
cookbook/decorator-pattern
|
||||
cookbook/dql-custom-walkers
|
||||
cookbook/dql-user-defined-functions
|
||||
cookbook/generated-columns
|
||||
cookbook/implementing-arrayaccess-for-domain-objects
|
||||
cookbook/resolve-target-entity-listener
|
||||
cookbook/sql-table-prefixes
|
||||
cookbook/strategy-cookbook-introduction
|
||||
cookbook/validation-of-entities
|
||||
cookbook/working-with-datetime
|
||||
cookbook/mysql-enums
|
||||
cookbook/advanced-field-value-conversion-using-custom-mapping-types
|
||||
cookbook/entities-in-session
|
||||
|
||||
@@ -50,43 +50,11 @@ and year of production as primary keys:
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
namespace VehicleCatalogue\Model;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class Car
|
||||
{
|
||||
/** @Id @Column(type="string") */
|
||||
private string $name;
|
||||
/** @Id @Column(type="integer") */
|
||||
private int $year;
|
||||
|
||||
public function __construct($name, $year)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->year = $year;
|
||||
}
|
||||
|
||||
public function getModelName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getYearOfProduction(): int
|
||||
{
|
||||
return $this->year;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
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">
|
||||
|
||||
@@ -96,16 +64,6 @@ and year of production as primary keys:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
VehicleCatalogue\Model\Car:
|
||||
type: entity
|
||||
id:
|
||||
name:
|
||||
type: string
|
||||
year:
|
||||
type: integer
|
||||
|
||||
Now you can use this entity:
|
||||
|
||||
.. code-block:: php
|
||||
@@ -127,11 +85,12 @@ And for querying you can use arrays to both DQL and EntityRepositories:
|
||||
namespace VehicleCatalogue\Model;
|
||||
|
||||
// $em is the EntityManager
|
||||
$audi = $em->find("VehicleCatalogue\Model\Car", array("name" => "Audi A8", "year" => 2010));
|
||||
$audi = $em->find("VehicleCatalogue\Model\Car", ["name" => "Audi A8", "year" => 2010]);
|
||||
|
||||
$dql = "SELECT c FROM VehicleCatalogue\Model\Car c WHERE c.id = ?1";
|
||||
$dql = "SELECT c FROM VehicleCatalogue\Model\Car c WHERE c.name = ?1 AND c.year = ?2";
|
||||
$audi = $em->createQuery($dql)
|
||||
->setParameter(1, ["name" => "Audi A8", "year" => 2010])
|
||||
->setParameter(1, "Audi A8")
|
||||
->setParameter(2, 2010)
|
||||
->getSingleResult();
|
||||
|
||||
You can also use this entity in associations. Doctrine will then generate two foreign keys one for ``name``
|
||||
@@ -160,7 +119,6 @@ The semantics of mapping identity through foreign entities are easy:
|
||||
- Only allowed on Many-To-One or One-To-One associations.
|
||||
- Plug an ``#[Id]`` attribute onto every association.
|
||||
- Set an attribute ``association-key`` with the field name of the association in XML.
|
||||
- Set a key ``associationKey:`` with the field name of the association in YAML.
|
||||
|
||||
Use-Case 1: Dynamic Attributes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -214,61 +172,10 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
namespace Application\Model;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class Article
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
private int|null $id = null;
|
||||
/** @Column(type="string") */
|
||||
private string $title;
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity="ArticleAttribute", mappedBy="article", cascade={"ALL"}, indexBy="attribute")
|
||||
* @var Collection<int, ArticleAttribute>
|
||||
*/
|
||||
private Collection $attributes;
|
||||
|
||||
public function addAttribute($name, $value): void
|
||||
{
|
||||
$this->attributes[$name] = new ArticleAttribute($name, $value, $this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class ArticleAttribute
|
||||
{
|
||||
/** @Id @ManyToOne(targetEntity="Article", inversedBy="attributes") */
|
||||
private Article|null $article;
|
||||
|
||||
/** @Id @Column(type="string") */
|
||||
private string $attribute;
|
||||
|
||||
/** @Column(type="string") */
|
||||
private string $value;
|
||||
|
||||
public function __construct($name, $value, $article)
|
||||
{
|
||||
$this->attribute = $name;
|
||||
$this->value = $value;
|
||||
$this->article = $article;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -283,24 +190,6 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Application\Model\ArticleAttribute:
|
||||
type: entity
|
||||
id:
|
||||
article:
|
||||
associationKey: true
|
||||
attribute:
|
||||
type: string
|
||||
fields:
|
||||
value:
|
||||
type: string
|
||||
manyToOne:
|
||||
article:
|
||||
targetEntity: Article
|
||||
inversedBy: attributes
|
||||
|
||||
|
||||
Use-Case 2: Simple Derived Identity
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -328,26 +217,6 @@ One good example for this is a user-address relationship:
|
||||
private User|null $user = null;
|
||||
}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
generator:
|
||||
strategy: AUTO
|
||||
|
||||
Address:
|
||||
type: entity
|
||||
id:
|
||||
user:
|
||||
associationKey: true
|
||||
oneToOne:
|
||||
user:
|
||||
targetEntity: User
|
||||
|
||||
|
||||
Use-Case 3: Join-Table with Metadata
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -381,7 +250,7 @@ of products purchased and maybe even the current price.
|
||||
|
||||
public function __construct(
|
||||
#[ManyToOne(targetEntity: Customer::class)]
|
||||
private Customer $customer,
|
||||
private Customer $customer
|
||||
) {
|
||||
$this->items = new ArrayCollection();
|
||||
$this->created = new DateTime("now");
|
||||
@@ -426,6 +295,7 @@ of products purchased and maybe even the current price.
|
||||
$this->order = $order;
|
||||
$this->product = $product;
|
||||
$this->offeredPrice = $product->getCurrentPrice();
|
||||
$this->amount = $amount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,33 +44,6 @@ instead of simply adding the respective columns to the ``User`` class.
|
||||
private string $country;
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
|
||||
/** @Entity */
|
||||
class User
|
||||
{
|
||||
/** @Embedded(class = "Address") */
|
||||
private Address $address;
|
||||
}
|
||||
|
||||
/** @Embeddable */
|
||||
class Address
|
||||
{
|
||||
/** @Column(type = "string") */
|
||||
private string $street;
|
||||
|
||||
/** @Column(type = "string") */
|
||||
private string $postalCode;
|
||||
|
||||
/** @Column(type = "string") */
|
||||
private string $city;
|
||||
|
||||
/** @Column(type = "string") */
|
||||
private string $country;
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -86,22 +59,6 @@ instead of simply adding the respective columns to the ``User`` class.
|
||||
</embeddable>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
embedded:
|
||||
address:
|
||||
class: Address
|
||||
|
||||
Address:
|
||||
type: embeddable
|
||||
fields:
|
||||
street: { type: string }
|
||||
postalCode: { type: string }
|
||||
city: { type: string }
|
||||
country: { type: string }
|
||||
|
||||
In terms of your database schema, Doctrine will automatically inline all
|
||||
columns from the ``Address`` class into the table of the ``User`` class,
|
||||
just as if you had declared them directly there.
|
||||
@@ -147,32 +104,12 @@ The following example shows you how to set your prefix to ``myPrefix_``:
|
||||
private Address $address;
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
|
||||
/** @Entity */
|
||||
class User
|
||||
{
|
||||
/** @Embedded(class = "Address", columnPrefix = "myPrefix_") */
|
||||
private $address;
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<entity name="User">
|
||||
<embedded name="address" class="Address" column-prefix="myPrefix_" />
|
||||
</entity>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
embedded:
|
||||
address:
|
||||
class: Address
|
||||
columnPrefix: myPrefix_
|
||||
|
||||
To have Doctrine drop the prefix and use the value object's property name
|
||||
directly, set ``columnPrefix=false`` (``use-column-prefix="false"`` for XML):
|
||||
|
||||
@@ -189,32 +126,12 @@ directly, set ``columnPrefix=false`` (``use-column-prefix="false"`` for XML):
|
||||
private Address $address;
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
|
||||
/** @Entity */
|
||||
class User
|
||||
{
|
||||
/** @Embedded(class = "Address", columnPrefix = false) */
|
||||
private Address $address;
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<entity name="User">
|
||||
<embedded name="address" class="Address" use-column-prefix="false" />
|
||||
</entity>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
embedded:
|
||||
address:
|
||||
class: Address
|
||||
columnPrefix: false
|
||||
|
||||
|
||||
DQL
|
||||
---
|
||||
|
||||
@@ -17,7 +17,9 @@ can be called without triggering a full load of the collection:
|
||||
- ``Collection#contains($entity)``
|
||||
- ``Collection#containsKey($key)``
|
||||
- ``Collection#count()``
|
||||
- ``Collection#first()``
|
||||
- ``Collection#get($key)``
|
||||
- ``Collection#isEmpty()``
|
||||
- ``Collection#slice($offset, $length = null)``
|
||||
|
||||
For each of the above methods the following semantics apply:
|
||||
@@ -65,28 +67,11 @@ switch to extra lazy as shown in these examples:
|
||||
public Collection $users;
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
namespace Doctrine\Tests\Models\CMS;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class CmsGroup
|
||||
{
|
||||
/**
|
||||
* @ManyToMany(targetEntity="CmsUser", mappedBy="groups", fetch="EXTRA_LAZY")
|
||||
* @var Collection<int, CmsUser>
|
||||
*/
|
||||
public Collection $users;
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
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">
|
||||
|
||||
@@ -95,14 +80,3 @@ switch to extra lazy as shown in these examples:
|
||||
<many-to-many field="users" target-entity="CmsUser" mapped-by="groups" fetch="EXTRA_LAZY" />
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Doctrine\Tests\Models\CMS\CmsGroup:
|
||||
type: entity
|
||||
# ...
|
||||
manyToMany:
|
||||
users:
|
||||
targetEntity: CmsUser
|
||||
mappedBy: groups
|
||||
fetch: EXTRA_LAZY
|
||||
|
||||
@@ -27,7 +27,7 @@ What is Doctrine?
|
||||
-----------------
|
||||
|
||||
Doctrine ORM is an `object-relational mapper (ORM) <https://en.wikipedia.org/wiki/Object-relational_mapping>`_
|
||||
for PHP 7.1+ that provides transparent persistence for PHP objects. It uses the Data Mapper
|
||||
for PHP that provides transparent persistence for PHP objects. It uses the Data Mapper
|
||||
pattern at the heart, aiming for a complete separation of your domain/business
|
||||
logic from the persistence in a relational database management system.
|
||||
|
||||
@@ -82,10 +82,9 @@ that directory with the following contents:
|
||||
|
||||
{
|
||||
"require": {
|
||||
"doctrine/orm": "^2.11.0",
|
||||
"doctrine/dbal": "^3.2",
|
||||
"symfony/yaml": "^5.4",
|
||||
"symfony/cache": "^5.4"
|
||||
"doctrine/orm": "^3",
|
||||
"doctrine/dbal": "^4",
|
||||
"symfony/cache": "^7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {"": "src/"}
|
||||
@@ -107,12 +106,8 @@ Add the following directories::
|
||||
doctrine2-tutorial
|
||||
|-- config
|
||||
| `-- xml
|
||||
| `-- yaml
|
||||
`-- src
|
||||
|
||||
.. note::
|
||||
The YAML driver is deprecated and will be removed in version 3.0.
|
||||
It is strongly recommended to switch to one of the other mappings.
|
||||
.. note::
|
||||
It is strongly recommended that you require ``doctrine/dbal`` in your
|
||||
``composer.json`` as well, because using the ORM means mapping objects
|
||||
@@ -143,23 +138,15 @@ 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 annotation, YAML or XML
|
||||
// $config = ORMSetup::createAnnotationMetadataConfiguration(
|
||||
// paths: array(__DIR__."/src"),
|
||||
// isDevMode: true,
|
||||
// );
|
||||
// $config = ORMSetup::createXMLMetadataConfiguration(
|
||||
// or if you prefer XML
|
||||
// $config = ORMSetup::createXMLMetadataConfig( // on PHP < 8.4, use ORMSetup::createXMLMetadataConfiguration()
|
||||
// paths: [__DIR__ . '/config/xml'],
|
||||
// isDevMode: true,
|
||||
//);
|
||||
// $config = ORMSetup::createYAMLMetadataConfiguration(
|
||||
// paths: array(__DIR__."/config/yaml"),
|
||||
// isDevMode: true,
|
||||
// );
|
||||
|
||||
// configuring the database connection
|
||||
$connection = DriverManager::getConnection([
|
||||
@@ -170,10 +157,6 @@ step:
|
||||
// obtaining the entity manager
|
||||
$entityManager = new EntityManager($connection, $config);
|
||||
|
||||
.. note::
|
||||
The YAML driver is deprecated and will be removed in version 3.0.
|
||||
It is strongly recommended to switch to one of the other mappings.
|
||||
|
||||
The ``require_once`` statement sets up the class autoloading for Doctrine and
|
||||
its dependencies using Composer's autoloader.
|
||||
|
||||
@@ -500,8 +483,8 @@ language describes how entities, their properties and references should be
|
||||
persisted and what constraints should be applied to them.
|
||||
|
||||
Metadata for an Entity can be configured using attributes directly in
|
||||
the Entity class itself, or in an external XML or YAML file. This
|
||||
Getting Started guide will demonstrate metadata mappings using all three
|
||||
the Entity class itself, or in an external XML file. This
|
||||
Getting Started guide will demonstrate metadata mappings using both
|
||||
methods, but you only need to choose one.
|
||||
|
||||
.. configuration-block::
|
||||
@@ -527,38 +510,11 @@ methods, but you only need to choose one.
|
||||
// .. (other code)
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
// src/Product.php
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="products")
|
||||
*/
|
||||
class Product
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
private int|null $id = null;
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
private string $name;
|
||||
|
||||
// .. (other code)
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/Product.dcm.xml -->
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -571,25 +527,6 @@ methods, but you only need to choose one.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. note::
|
||||
The YAML driver is deprecated and will be removed in version 3.0.
|
||||
It is strongly recommended to switch to one of the other mappings.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/yaml/Product.dcm.yml
|
||||
Product:
|
||||
type: entity
|
||||
table: products
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
generator:
|
||||
strategy: AUTO
|
||||
fields:
|
||||
name:
|
||||
type: string
|
||||
|
||||
The top-level ``entity`` definition specifies information about
|
||||
the class and table name. The primitive type ``Product#name`` is
|
||||
defined as a ``field`` attribute. The ``id`` property is defined with
|
||||
@@ -1082,64 +1019,11 @@ the ``Product`` before:
|
||||
// ... (other code)
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
// src/Bug.php
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="bugs")
|
||||
*/
|
||||
class Bug
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
private int|null $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
private string $description;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime")
|
||||
*/
|
||||
private DateTime $created;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
private string $status;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="User", inversedBy="assignedBugs")
|
||||
*/
|
||||
private User|null $engineer;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="User", inversedBy="reportedBugs")
|
||||
*/
|
||||
private User|null $reporter;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity="Product")
|
||||
*/
|
||||
private Collection $products;
|
||||
|
||||
// ... (other code)
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/Bug.dcm.xml -->
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -1159,40 +1043,6 @@ the ``Product`` before:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. note::
|
||||
The YAML driver is deprecated and will be removed in version 3.0.
|
||||
It is strongly recommended to switch to one of the other mappings.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/yaml/Bug.dcm.yml
|
||||
Bug:
|
||||
type: entity
|
||||
table: bugs
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
generator:
|
||||
strategy: AUTO
|
||||
fields:
|
||||
description:
|
||||
type: text
|
||||
created:
|
||||
type: datetime
|
||||
status:
|
||||
type: string
|
||||
manyToOne:
|
||||
reporter:
|
||||
targetEntity: User
|
||||
inversedBy: reportedBugs
|
||||
engineer:
|
||||
targetEntity: User
|
||||
inversedBy: assignedBugs
|
||||
manyToMany:
|
||||
products:
|
||||
targetEntity: Product
|
||||
|
||||
|
||||
Here we have the entity, id and primitive type definitions.
|
||||
For the "created" field we have used the ``datetime`` type,
|
||||
which translates the YYYY-mm-dd HH:mm:ss database format
|
||||
@@ -1249,52 +1099,11 @@ Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
// .. (other code)
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
// src/User.php
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="users")
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
private int|null $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
* @var string
|
||||
*/
|
||||
private string $name;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="Bug", mappedBy="reporter")
|
||||
* @var Collection<int, Bug> An ArrayCollection of Bug objects.
|
||||
*/
|
||||
private Collection $reportedBugs;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="Bug", mappedBy="engineer")
|
||||
* @var Collection<int, Bug> An ArrayCollection of Bug objects.
|
||||
*/
|
||||
private Collection $assignedBugs;
|
||||
|
||||
// .. (other code)
|
||||
}
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/User.dcm.xml -->
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -1310,33 +1119,7 @@ Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. note::
|
||||
The YAML driver is deprecated and will be removed in version 3.0.
|
||||
It is strongly recommended to switch to one of the other mappings.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/yaml/User.dcm.yml
|
||||
User:
|
||||
type: entity
|
||||
table: users
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
generator:
|
||||
strategy: AUTO
|
||||
fields:
|
||||
name:
|
||||
type: string
|
||||
oneToMany:
|
||||
reportedBugs:
|
||||
targetEntity: Bug
|
||||
mappedBy: reporter
|
||||
assignedBugs:
|
||||
targetEntity: Bug
|
||||
mappedBy: engineer
|
||||
|
||||
Here are some new things to mention about the ``OneToMany`` attribute.
|
||||
Here are some new things to mention about the ``one-to-many`` tags.
|
||||
Remember that we discussed about the inverse and owning side. Now
|
||||
both reportedBugs and assignedBugs are inverse relations, which
|
||||
means the join details have already been defined on the owning
|
||||
@@ -1800,25 +1583,10 @@ we have to adjust the metadata slightly.
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass="BugRepository")
|
||||
* @ORM\Table(name="bugs")
|
||||
*/
|
||||
class Bug
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
@@ -1827,16 +1595,6 @@ we have to adjust the metadata slightly.
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. note::
|
||||
The YAML driver is deprecated and will be removed in version 3.0.
|
||||
It is strongly recommended to switch to one of the other mappings.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Bug:
|
||||
type: entity
|
||||
repositoryClass: BugRepository
|
||||
|
||||
Now we can remove our query logic in all the places and instead use them through the EntityRepository.
|
||||
As an example here is the code of the first use case "List of Bugs":
|
||||
|
||||
|
||||
@@ -27,22 +27,6 @@ can specify the ``#[OrderBy]`` in the following way:
|
||||
private Collection $groups;
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/** @Entity **/
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="Group")
|
||||
* @OrderBy({"name" = "ASC"})
|
||||
* @var Collection<int, Group>
|
||||
*/
|
||||
private Collection $groups;
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -55,23 +39,6 @@ can specify the ``#[OrderBy]`` in the following way:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
manyToMany:
|
||||
groups:
|
||||
orderBy: { 'name': 'ASC' }
|
||||
targetEntity: Group
|
||||
joinTable:
|
||||
name: users_groups
|
||||
joinColumns:
|
||||
user_id:
|
||||
referencedColumnName: id
|
||||
inverseJoinColumns:
|
||||
group_id:
|
||||
referencedColumnName: id
|
||||
|
||||
The DQL Snippet in OrderBy is only allowed to consist of
|
||||
unqualified, unquoted field names and of an optional ASC/DESC
|
||||
positional statement. Multiple Fields are separated by a comma (,).
|
||||
|
||||
@@ -9,7 +9,7 @@ i.e. attributes and associations metadata in particular. The example here shows
|
||||
the overriding of a class that uses a trait but is similar when extending a base
|
||||
class as shown at the end of this tutorial.
|
||||
|
||||
Suppose we have a class ExampleEntityWithOverride. This class uses trait ExampleTrait:
|
||||
Suppose we have a class ``ExampleEntityWithOverride``. This class uses trait ``ExampleTrait``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -17,22 +17,20 @@ Suppose we have a class ExampleEntityWithOverride. This class uses trait Example
|
||||
|
||||
#[Entity]
|
||||
#[AttributeOverrides([
|
||||
new AttributeOverride('foo', [
|
||||
'column' => new Column([
|
||||
'name' => 'foo_overridden',
|
||||
'type' => 'integer',
|
||||
'length' => 140,
|
||||
'nullable' => false,
|
||||
'unique' => false,
|
||||
]),
|
||||
]),
|
||||
new AttributeOverride('foo', new Column(
|
||||
name: 'foo_overridden',
|
||||
type: 'integer',
|
||||
length: 140,
|
||||
nullable: false,
|
||||
unique: false,
|
||||
)),
|
||||
])]
|
||||
#[AssociationOverrides([
|
||||
new AssociationOverride('bar', [
|
||||
'joinColumns' => new JoinColumn([
|
||||
'name' => 'example_entity_overridden_bar_id',
|
||||
'referencedColumnName' => 'id',
|
||||
]),
|
||||
new JoinColumn(
|
||||
name: 'example_entity_overridden_bar_id',
|
||||
referencedColumnName: 'id',
|
||||
),
|
||||
]),
|
||||
])]
|
||||
class ExampleEntityWithOverride
|
||||
@@ -47,7 +45,7 @@ Suppose we have a class ExampleEntityWithOverride. This class uses trait Example
|
||||
private $id;
|
||||
}
|
||||
|
||||
The docblock is showing metadata override of the attribute and association type. It
|
||||
``#[AttributeOverrides]`` contains metadata override of the attribute and association type. It
|
||||
basically changes the names of the columns mapped for a property ``foo`` and for
|
||||
the association ``bar`` which relates to Bar class shown above. Here is the trait
|
||||
which has mapping metadata that is overridden by the attribute above:
|
||||
@@ -66,7 +64,7 @@ which has mapping metadata that is overridden by the attribute above:
|
||||
#[Column(name: 'trait_foo', type: 'integer', length: 100, nullable: true, unique: true)]
|
||||
protected int $foo;
|
||||
|
||||
#[OneToOne(targetEntity: Bar::class, cascade: ['persist', 'merge'])]
|
||||
#[OneToOne(targetEntity: Bar::class, cascade: ['persist'])]
|
||||
#[JoinColumn(name: 'example_trait_bar_id', referencedColumnName: 'id')]
|
||||
protected Bar|null $bar = null;
|
||||
}
|
||||
@@ -81,4 +79,4 @@ The case for just extending a class would be just the same but:
|
||||
// ...
|
||||
}
|
||||
|
||||
Overriding is also supported via XML and YAML (:ref:`examples <inheritence_mapping_overrides>`).
|
||||
Overriding is also supported via XML (:ref:`examples <inheritence_mapping_overrides>`).
|
||||
|
||||
@@ -24,176 +24,16 @@ Mapping Indexed Associations
|
||||
You can map indexed associations by adding:
|
||||
|
||||
* ``indexBy`` argument to any ``#[OneToMany]`` or ``#[ManyToMany]`` attribute.
|
||||
* ``indexBy`` attribute to any ``@OneToMany`` or ``@ManyToMany`` annotation.
|
||||
* ``index-by`` attribute to any ``<one-to-many />`` or ``<many-to-many />`` xml element.
|
||||
* ``indexBy:`` key-value pair to any association defined in ``manyToMany:`` or ``oneToMany:`` YAML mapping files.
|
||||
|
||||
The code and mappings for the Market entity looks like this:
|
||||
|
||||
.. configuration-block::
|
||||
.. code-block:: attribute
|
||||
.. literalinclude:: working-with-indexed-associations/Market.php
|
||||
:language: attribute
|
||||
|
||||
<?php
|
||||
namespace Doctrine\Tests\Models\StockExchange;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
#[Entity]
|
||||
#[Table(name: 'exchange_markets')]
|
||||
class Market
|
||||
{
|
||||
#[Id, Column(type: 'integer'), GeneratedValue]
|
||||
private int|null $id = null;
|
||||
|
||||
#[Column(type: 'string')]
|
||||
private string $name;
|
||||
|
||||
/** @var Collection<string, Stock> */
|
||||
#[OneToMany(targetEntity: Stock::class, mappedBy: 'market', indexBy: 'symbol')]
|
||||
private Collection $stocks;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->stocks = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): int|null
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function addStock(Stock $stock): void
|
||||
{
|
||||
$this->stocks[$stock->getSymbol()] = $stock;
|
||||
}
|
||||
|
||||
public function getStock(string $symbol): Stock
|
||||
{
|
||||
if (!isset($this->stocks[$symbol])) {
|
||||
throw new \InvalidArgumentException("Symbol is not traded on this market.");
|
||||
}
|
||||
|
||||
return $this->stocks[$symbol];
|
||||
}
|
||||
|
||||
/** @return array<string, Stock> */
|
||||
public function getStocks(): array
|
||||
{
|
||||
return $this->stocks->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
namespace Doctrine\Tests\Models\StockExchange;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="exchange_markets")
|
||||
*/
|
||||
class Market
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer") @GeneratedValue
|
||||
* @var int
|
||||
*/
|
||||
private int|null $id = null;
|
||||
|
||||
/**
|
||||
* @Column(type="string")
|
||||
* @var string
|
||||
*/
|
||||
private string $name;
|
||||
|
||||
/**
|
||||
* @OneToMany(targetEntity="Stock", mappedBy="market", indexBy="symbol")
|
||||
* @var Collection<int, Stock>
|
||||
*/
|
||||
private Collection $stocks;
|
||||
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->stocks = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): int|null
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function addStock(Stock $stock): void
|
||||
{
|
||||
$this->stocks[$stock->getSymbol()] = $stock;
|
||||
}
|
||||
|
||||
public function getStock($symbol): Stock
|
||||
{
|
||||
if (!isset($this->stocks[$symbol])) {
|
||||
throw new \InvalidArgumentException("Symbol is not traded on this market.");
|
||||
}
|
||||
|
||||
return $this->stocks[$symbol];
|
||||
}
|
||||
|
||||
/** @return array<string, Stock> */
|
||||
public function getStocks(): array
|
||||
{
|
||||
return $this->stocks->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\StockExchange\Market">
|
||||
<id name="id" type="integer">
|
||||
<generator strategy="AUTO" />
|
||||
</id>
|
||||
|
||||
<field name="name" type="string"/>
|
||||
|
||||
<one-to-many target-entity="Stock" mapped-by="market" field="stocks" index-by="symbol" />
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Doctrine\Tests\Models\StockExchange\Market:
|
||||
type: entity
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
generator:
|
||||
strategy: AUTO
|
||||
fields:
|
||||
name:
|
||||
type:string
|
||||
oneToMany:
|
||||
stocks:
|
||||
targetEntity: Stock
|
||||
mappedBy: market
|
||||
indexBy: symbol
|
||||
.. literalinclude:: working-with-indexed-associations/market.xml
|
||||
:language: xml
|
||||
|
||||
Inside the ``addStock()`` method you can see how we directly set the key of the association to the symbol,
|
||||
so that we can work with the indexed association directly after invoking ``addStock()``. Inside ``getStock($symbol)``
|
||||
@@ -234,52 +74,11 @@ here are the code and mappings for it:
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
namespace Doctrine\Tests\Models\StockExchange;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="exchange_stocks")
|
||||
*/
|
||||
class Stock
|
||||
{
|
||||
/**
|
||||
* @Id @GeneratedValue @Column(type="integer")
|
||||
* @var int
|
||||
*/
|
||||
private int|null $id = null;
|
||||
|
||||
/**
|
||||
* @Column(type="string", unique=true)
|
||||
*/
|
||||
private string $symbol;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="Market", inversedBy="stocks")
|
||||
* @var Market
|
||||
*/
|
||||
private Market|null $market = null;
|
||||
|
||||
public function __construct($symbol, Market $market)
|
||||
{
|
||||
$this->symbol = $symbol;
|
||||
$this->market = $market;
|
||||
$market->addStock($this);
|
||||
}
|
||||
|
||||
public function getSymbol(): string
|
||||
{
|
||||
return $this->symbol;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
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">
|
||||
|
||||
@@ -293,23 +92,6 @@ here are the code and mappings for it:
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Doctrine\Tests\Models\StockExchange\Stock:
|
||||
type: entity
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
generator:
|
||||
strategy: AUTO
|
||||
fields:
|
||||
symbol:
|
||||
type: string
|
||||
manyToOne:
|
||||
market:
|
||||
targetEntity: Market
|
||||
inversedBy: stocks
|
||||
|
||||
Querying indexed associations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Tests\Models\StockExchange;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\GeneratedValue;
|
||||
use Doctrine\ORM\Mapping\Id;
|
||||
use Doctrine\ORM\Mapping\OneToMany;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
use InvalidArgumentException;
|
||||
|
||||
#[Entity]
|
||||
#[Table(name: 'exchange_markets')]
|
||||
class Market
|
||||
{
|
||||
#[Id]
|
||||
#[Column(type: 'integer')]
|
||||
#[GeneratedValue]
|
||||
private int|null $id = null;
|
||||
|
||||
#[Column(type: 'string')]
|
||||
private string $name;
|
||||
|
||||
/** @var Collection<string, Stock> */
|
||||
#[OneToMany(targetEntity: Stock::class, mappedBy: 'market', indexBy: 'symbol')]
|
||||
private Collection $stocks;
|
||||
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->stocks = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): int|null
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function addStock(Stock $stock): void
|
||||
{
|
||||
$this->stocks[$stock->getSymbol()] = $stock;
|
||||
}
|
||||
|
||||
public function getStock(string $symbol): Stock
|
||||
{
|
||||
if (! isset($this->stocks[$symbol])) {
|
||||
throw new InvalidArgumentException('Symbol is not traded on this market.');
|
||||
}
|
||||
|
||||
return $this->stocks[$symbol];
|
||||
}
|
||||
|
||||
/** @return array<string, Stock> */
|
||||
public function getStocks(): array
|
||||
{
|
||||
return $this->stocks->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\StockExchange\Market">
|
||||
<id name="id" type="integer">
|
||||
<generator strategy="AUTO" />
|
||||
</id>
|
||||
|
||||
<field name="name" type="string"/>
|
||||
|
||||
<one-to-many target-entity="Stock" mapped-by="market" field="stocks" index-by="symbol" />
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
@@ -35,7 +35,6 @@
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="cascade-all" type="orm:emptyType" minOccurs="0"/>
|
||||
<xs:element name="cascade-persist" type="orm:emptyType" minOccurs="0"/>
|
||||
<xs:element name="cascade-merge" type="orm:emptyType" minOccurs="0"/>
|
||||
<xs:element name="cascade-remove" type="orm:emptyType" minOccurs="0"/>
|
||||
<xs:element name="cascade-refresh" type="orm:emptyType" minOccurs="0"/>
|
||||
<xs:element name="cascade-detach" type="orm:emptyType" minOccurs="0"/>
|
||||
@@ -82,36 +81,6 @@
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="named-query">
|
||||
<xs:attribute name="name" type="xs:string" use="required" />
|
||||
<xs:attribute name="query" type="xs:string" use="required" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="named-queries">
|
||||
<xs:sequence>
|
||||
<xs:element name="named-query" type="orm:named-query" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="named-native-query">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="query" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:string" use="required" />
|
||||
<xs:attribute name="result-class" type="orm:fqcn" />
|
||||
<xs:attribute name="result-set-mapping" type="xs:string" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="named-native-queries">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="named-native-query" type="orm:named-native-query" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="entity-listener">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="lifecycle-callback" type="orm:lifecycle-callback" minOccurs="0" maxOccurs="unbounded"/>
|
||||
@@ -143,23 +112,6 @@
|
||||
<xs:attribute name="discriminator-column" type="xs:string" use="optional" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="sql-result-set-mapping">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="entity-result" type="orm:entity-result"/>
|
||||
<xs:element name="column-result" type="orm:column-result"/>
|
||||
</xs:choice>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:string" use="required" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="sql-result-set-mappings">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="sql-result-set-mapping" type="orm:sql-result-set-mapping" minOccurs="1" maxOccurs="unbounded" />
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="cache">
|
||||
<xs:attribute name="usage" type="orm:cache-usage-type" />
|
||||
<xs:attribute name="region" type="xs:string" />
|
||||
@@ -175,9 +127,6 @@
|
||||
<xs:element name="discriminator-map" type="orm:discriminator-map" minOccurs="0"/>
|
||||
<xs:element name="lifecycle-callbacks" type="orm:lifecycle-callbacks" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="entity-listeners" type="orm:entity-listeners" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="named-queries" type="orm:named-queries" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="named-native-queries" type="orm:named-native-queries" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="sql-result-set-mappings" type="orm:sql-result-set-mappings" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="id" type="orm:id" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="field" type="orm:field" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="embedded" type="orm:embedded" minOccurs="0" maxOccurs="unbounded"/>
|
||||
@@ -239,7 +188,6 @@
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="DEFERRED_IMPLICIT"/>
|
||||
<xs:enumeration value="DEFERRED_EXPLICIT"/>
|
||||
<xs:enumeration value="NOTIFY"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
@@ -247,7 +195,6 @@
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="SINGLE_TABLE"/>
|
||||
<xs:enumeration value="JOINED"/>
|
||||
<xs:enumeration value="TABLE_PER_CLASS"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
@@ -257,7 +204,6 @@
|
||||
<xs:enumeration value="SEQUENCE"/>
|
||||
<xs:enumeration value="IDENTITY"/>
|
||||
<xs:enumeration value="AUTO"/>
|
||||
<xs:enumeration value="UUID"/>
|
||||
<xs:enumeration value="CUSTOM" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
@@ -297,6 +243,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" />
|
||||
@@ -375,7 +322,7 @@
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="value" type="xs:NMTOKEN" use="required"/>
|
||||
<xs:attribute name="value" type="orm:type" use="required"/>
|
||||
<xs:attribute name="class" type="orm:fqcn" use="required"/>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
108
phpcs.xml.dist
108
phpcs.xml.dist
@@ -1,5 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset>
|
||||
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
name="PHP_CodeSniffer"
|
||||
xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
|
||||
<arg name="basepath" value="."/>
|
||||
<arg name="extensions" value="php"/>
|
||||
<arg name="parallel" value="80"/>
|
||||
@@ -9,7 +11,7 @@
|
||||
<!-- Ignore warnings, show progress of the run and show sniff names -->
|
||||
<arg value="nps"/>
|
||||
|
||||
<config name="php_version" value="70100"/>
|
||||
<config name="php_version" value="80100"/>
|
||||
|
||||
<file>src</file>
|
||||
<file>tests</file>
|
||||
@@ -18,38 +20,38 @@
|
||||
<exclude-pattern>*/tests/Tests/ORM/Tools/Export/export/*</exclude-pattern>
|
||||
|
||||
<rule ref="Doctrine">
|
||||
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint" />
|
||||
<exclude name="SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingReturnTypeHint"/>
|
||||
<exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint" />
|
||||
<exclude name="SlevomatCodingStandard.Exceptions.ReferenceThrowableOnly.ReferencedGeneralException"/>
|
||||
<exclude name="SlevomatCodingStandard.ControlStructures.EarlyExit"/>
|
||||
<exclude name="SlevomatCodingStandard.Classes.SuperfluousAbstractClassNaming"/>
|
||||
<exclude name="SlevomatCodingStandard.Classes.SuperfluousExceptionNaming"/>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Commenting.RequireOneLineDocComment.MultiLineDocComment">
|
||||
<!-- Remove when dropping PHPUnit 7 -->
|
||||
<exclude-pattern>*/tests/*</exclude-pattern>
|
||||
<exclude name="SlevomatCodingStandard.Classes.ModernClassNameReference.ClassNameReferencedViaFunctionCall"/>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint">
|
||||
<exclude-pattern>*/src/*</exclude-pattern>
|
||||
<!--
|
||||
that class extends another one inside src/ and can therefore not
|
||||
have more native typehints since its parent cannot have them: that
|
||||
would break signature compatibility.
|
||||
-->
|
||||
<exclude-pattern>tests/Tests/Mocks/HydratorMockStatement.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Models/Cache/ComplexAction.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Models/DDC117/DDC117ArticleDetails.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Models/DDC117/DDC117Translation.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC2579Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/ValueObjectsTest.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint">
|
||||
<exclude-pattern>*/src/*</exclude-pattern>
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint">
|
||||
<exclude-pattern>tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint">
|
||||
<exclude-pattern>tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="PSR1.Classes.ClassDeclaration.MultipleClasses">
|
||||
<exclude-pattern>src/Mapping/Driver/CompatibilityAnnotationDriver.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Console/CommandCompatibility.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Console/Helper/EntityManagerHelper.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/Driver/LoadMappingFileImplementation.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/GetReflectionClassImplementation.php</exclude-pattern>
|
||||
<exclude-pattern>tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
@@ -68,14 +70,6 @@
|
||||
<exclude-pattern>src/Tools/ToolEvents.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingTraversableTypeHintSpecification">
|
||||
<!-- https://github.com/doctrine/annotations/issues/129 -->
|
||||
<exclude-pattern>src/Mapping/Column.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/Index.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/Table.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/UniqueConstraint.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Operators.DisallowEqualOperators.DisallowedNotEqualOperator">
|
||||
<exclude-pattern>src/Internal/Hydration/AbstractHydrator.php</exclude-pattern>
|
||||
</rule>
|
||||
@@ -92,7 +86,6 @@
|
||||
<exclude-pattern>src/Mapping/Cache.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/ChangeTrackingPolicy.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/Column.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/ColumnResult.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/CustomIdGenerator.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/DiscriminatorColumn.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/DiscriminatorMap.php</exclude-pattern>
|
||||
@@ -100,8 +93,6 @@
|
||||
<exclude-pattern>src/Mapping/Embedded.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/Entity.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/EntityListeners.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/EntityResult.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/FieldResult.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/GeneratedValue.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/HasLifecycleCallbacks.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/Id.php</exclude-pattern>
|
||||
@@ -113,10 +104,6 @@
|
||||
<exclude-pattern>src/Mapping/ManyToMany.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/ManyToOne.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/MappedSuperclass.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/NamedNativeQueries.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/NamedNativeQuery.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/NamedQueries.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/NamedQuery.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/OneToMany.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/OneToOne.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/OrderBy.php</exclude-pattern>
|
||||
@@ -129,8 +116,6 @@
|
||||
<exclude-pattern>src/Mapping/PreRemove.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/PreUpdate.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/SequenceGenerator.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/SqlResultSetMapping.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/SqlResultSetMappings.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/Table.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/UniqueConstraint.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/Version.php</exclude-pattern>
|
||||
@@ -140,6 +125,36 @@
|
||||
<exclude-pattern>src/Cache/DefaultQueryCache.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Commenting.ForbiddenAnnotations">
|
||||
<properties>
|
||||
<property name="forbiddenAnnotations" type="array">
|
||||
<!--
|
||||
From Doctrine Coding Standard:
|
||||
Forbid useless annotations - Git and LICENCE file provide more accurate information
|
||||
-->
|
||||
<element value="@api"/>
|
||||
<element value="@author"/>
|
||||
<element value="@category"/>
|
||||
<element value="@copyright"/>
|
||||
<element value="@created"/>
|
||||
<element value="@license"/>
|
||||
<element value="@package"/>
|
||||
<element value="@since"/>
|
||||
<element value="@subpackage"/>
|
||||
<element value="@version"/>
|
||||
|
||||
<!-- Additionally forbid oldschool PHPUnit annotations to force the usage of attributes -->
|
||||
<element value="@covers"/>
|
||||
<element value="@depends"/>
|
||||
<element value="@dataProvider"/>
|
||||
<element value="@group"/>
|
||||
<element value="@requires"/>
|
||||
<element value="@test"/>
|
||||
<element value="@testWith"/>
|
||||
</property>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Classes.SuperfluousInterfaceNaming">
|
||||
<exclude-pattern>src/EntityManagerInterface.php</exclude-pattern>
|
||||
</rule>
|
||||
@@ -195,9 +210,6 @@
|
||||
<exclude-pattern>tests/Tests/Models/DDC1590/DDC1590User.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Commenting.ForbiddenAnnotations.AnnotationForbidden">
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC832Test.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.Classes.ValidClassName.NotCamelCaps">
|
||||
<!-- we need to test what happens with an stdClass proxy -->
|
||||
@@ -222,34 +234,20 @@
|
||||
|
||||
<rule ref="PSR2.Methods.MethodDeclaration.Underscore">
|
||||
<exclude-pattern>src/AbstractQuery.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/ClassMetadataInfo.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/ClassMetadata.php</exclude-pattern>
|
||||
<exclude-pattern>src/NativeQuery.php</exclude-pattern>
|
||||
<exclude-pattern>src/Query.php</exclude-pattern>
|
||||
<exclude-pattern>src/Query/TreeWalkerAdapter.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Export/Driver/AbstractExporter.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Export/Driver/AnnotationExporter.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Export/Driver/PhpExporter.php</exclude-pattern>
|
||||
<!-- extending a class from another package -->
|
||||
<exclude-pattern>tests/Tests/Mocks/DatabasePlatformMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Mocks/SchemaManagerMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/AbstractQueryTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC3634Test.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.NamingConventions.ValidVariableName.PublicHasUnderscore">
|
||||
<exclude-pattern>src/AbstractQuery.php</exclude-pattern>
|
||||
<exclude-pattern>src/Configuration.php</exclude-pattern>
|
||||
<exclude-pattern>src/EntityRepository.php</exclude-pattern>
|
||||
<exclude-pattern>src/Internal/Hydration/AbstractHydrator.php</exclude-pattern>
|
||||
<exclude-pattern>src/Query/Exec/AbstractSqlExecutor.php</exclude-pattern>
|
||||
<exclude-pattern>src/Query/Exec/AbstractSqlExecutor.php</exclude-pattern>
|
||||
<exclude-pattern>src/Query/Printer.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/EntityRepositoryGenerator.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Console/Helper/EntityManagerHelper.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Export/Driver/AbstractExporter.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Export/Driver/AnnotationExporter.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Export/Driver/PhpExporter.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Export/Driver/XmlExporter.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Export/Driver/YamlExporter.php</exclude-pattern>
|
||||
<!-- the impact of changing this would be too big -->
|
||||
<exclude-pattern>tests/Tests/OrmFunctionalTestCase.php</exclude-pattern>
|
||||
</rule>
|
||||
@@ -264,6 +262,7 @@
|
||||
<!-- Using @group and Group entity in the same file -->
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC1885Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC1843Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Mapping/ClassMetadataFactoryTest.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="Generic.CodeAnalysis.EmptyStatement.DetectedElse">
|
||||
@@ -278,9 +277,4 @@
|
||||
<!-- https://github.com/doctrine/orm/issues/8537 -->
|
||||
<exclude-pattern>src/QueryBuilder.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.PHP.UselessParentheses">
|
||||
<!-- We need those parentheses to make enum access seem like valid syntax on PHP 7 -->
|
||||
<exclude-pattern>src/Mapping/Driver/XmlDriver.php</exclude-pattern>
|
||||
</rule>
|
||||
</ruleset>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
includes:
|
||||
- phpstan-baseline.neon
|
||||
- phpstan-params.neon
|
||||
|
||||
parameters:
|
||||
reportUnmatchedIgnoredErrors: false
|
||||
|
||||
ignoreErrors:
|
||||
# PHPStan doesn't understand our method_exists() safeguards.
|
||||
- '/Call to an undefined method Doctrine\\DBAL\\Connection::createSchemaManager\(\)\./'
|
||||
# Class name will change in DBAL 3.
|
||||
- '/^Class Doctrine\\DBAL\\Platforms\\PostgreSQLPlatform not found\.$/'
|
||||
- '/^Class Doctrine\\DBAL\\Platforms\\AbstractMySQLPlatform not found\.$/'
|
||||
- '/^Class Doctrine\\DBAL\\Platforms\\MySQLPlatform not found\.$/'
|
||||
-
|
||||
message: '/Doctrine\\DBAL\\Platforms\\MyS(ql|QL)Platform/'
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
# Forward compatibility for DBAL 3.5
|
||||
- '/^Call to an undefined method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getAlterSchemaSQL\(\).$/'
|
||||
|
||||
# Forward compatibility for DBAL 3.4
|
||||
- '/^Call to an undefined method Doctrine\\DBAL\\Cache\\QueryCacheProfile::[gs]etResultCache\(\)\.$/'
|
||||
-
|
||||
message: '/^Call to an undefined static method Doctrine\\DBAL\\Configuration::[gs]etResultCache\(\)\.$/'
|
||||
path: src/Configuration.php
|
||||
-
|
||||
message: '/^Parameter #3 \$resultCache of class Doctrine\\DBAL\\Cache\\QueryCacheProfile constructor/'
|
||||
path: src/AbstractQuery.php
|
||||
-
|
||||
message: '/^Parameter #2 \$\w+ of method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getDateAdd\w+Expression\(\) expects int, string given\.$/'
|
||||
path: src/Query/AST/Functions/DateAddFunction.php
|
||||
-
|
||||
message: '/^Parameter #2 \$\w+ of method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getDateSub\w+Expression\(\) expects int, string given\.$/'
|
||||
path: src/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
# False positive
|
||||
-
|
||||
message: '/^Call to an undefined method Doctrine\\Common\\Cache\\Cache::deleteAll\(\)\.$/'
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/ClearCache/ResultCommand.php
|
||||
# See https://github.com/doctrine/dbal/pull/5129
|
||||
-
|
||||
message: '/^Parameter #3 \$startPos of method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getLocateExpression\(\) expects int\|false, string given\.$/'
|
||||
count: 1
|
||||
path: src/Query/AST/Functions/LocateFunction.php
|
||||
|
||||
# Won't get fixed in DBAL 2
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$start of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getSubstringExpression\\(\\) expects int, string given\\.$#"
|
||||
count: 1
|
||||
path: src/Query/AST/Functions/SubstringFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$length of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getSubstringExpression\\(\\) expects int\\|null, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Query/AST/Functions/SubstringFunction.php
|
||||
|
||||
-
|
||||
message: '#^Class Doctrine\\DBAL\\Platforms\\MySQLPlatform not found\.$#'
|
||||
count: 2
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
# Symfony cache supports passing a key prefix to the clear method.
|
||||
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
|
||||
|
||||
# Persistence 2 support
|
||||
-
|
||||
message: '/clear.*invoked with 1 parameter/'
|
||||
path: src/EntityRepository.php
|
||||
-
|
||||
message: '#^Class Doctrine\\Persistence\\ObjectManagerAware not found\.$#'
|
||||
path: src/UnitOfWork.php
|
||||
-
|
||||
message: '#^Call to method injectObjectManager\(\) on an unknown class Doctrine\\Persistence\\ObjectManagerAware\.$#'
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '#contains generic type.*but class.*is not generic#'
|
||||
paths:
|
||||
- src/Mapping/Driver/XmlDriver.php
|
||||
- src/Mapping/Driver/YamlDriver.php
|
||||
139
phpstan-dbal3.neon
Normal file
139
phpstan-dbal3.neon
Normal file
@@ -0,0 +1,139 @@
|
||||
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
|
||||
|
||||
-
|
||||
message: '~^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint::get.*\.$~'
|
||||
identifier: method.notFound
|
||||
|
||||
-
|
||||
message: '~createComparator~'
|
||||
identifier: arguments.count
|
||||
|
||||
-
|
||||
message: '~UnqualifiedName~'
|
||||
identifier: class.notFound
|
||||
|
||||
-
|
||||
message: '~IndexedColumn~'
|
||||
identifier: class.notFound
|
||||
|
||||
-
|
||||
message: '~PrimaryKeyConstraint~'
|
||||
identifier: class.notFound
|
||||
|
||||
-
|
||||
message: '~IndexType~'
|
||||
identifier: class.notFound
|
||||
|
||||
-
|
||||
message: '~dropForeignKey~'
|
||||
identifier: method.notFound
|
||||
|
||||
-
|
||||
message: '~getIndexedColumns~'
|
||||
identifier: method.notFound
|
||||
|
||||
-
|
||||
message: '~getPrimaryKeyConstraint~'
|
||||
identifier: method.notFound
|
||||
|
||||
-
|
||||
message: '~PrimaryKeyConstraint~'
|
||||
identifier: class.notFound
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: '~^Call to method toString.*UnqualifiedName\.$~'
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
- '~^Class Doctrine\\DBAL\\Platforms\\SQLitePlatform not found\.$~'
|
||||
|
||||
-
|
||||
message: '~sort~'
|
||||
identifier: argument.unresolvableType
|
||||
path: src/Mapping/Driver/DatabaseDriver.php
|
||||
|
||||
# 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
|
||||
@@ -1,5 +1,5 @@
|
||||
parameters:
|
||||
level: 5
|
||||
level: 7
|
||||
paths:
|
||||
- src
|
||||
- tests/StaticAnalysis
|
||||
@@ -8,8 +8,4 @@ parameters:
|
||||
earlyTerminatingMethodCalls:
|
||||
Doctrine\ORM\Query\Parser:
|
||||
- syntaxError
|
||||
phpVersion: 80200
|
||||
|
||||
ignoreErrors:
|
||||
# Remove on 3.0.x
|
||||
- '~^Default value of the parameter #2 \$value \(array\{\}\) of method Doctrine\\ORM\\Query\\AST\\InstanceOfExpression\:\:__construct\(\) is incompatible with type non\-empty\-array<int, Doctrine\\ORM\\Query\\AST\\InputParameter\|string>\.$~'
|
||||
phpVersion: 80400
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
includes:
|
||||
- phpstan-baseline.neon
|
||||
- phpstan-params.neon
|
||||
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
# deprecations from doctrine/dbal:3.x
|
||||
- '/^Call to an undefined method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getGuidExpression\(\).$/'
|
||||
|
||||
# Fallback logic for DBAL 2
|
||||
-
|
||||
message: '/Application::add\(\) expects Symfony\\Component\\Console\\Command\\Command/'
|
||||
path: src/Tools/Console/ConsoleRunner.php
|
||||
|
||||
- '/^Class Doctrine\\DBAL\\Platforms\\SQLAnywherePlatform not found\.$/'
|
||||
- '/^Call to method \w+\(\) on an unknown class Doctrine\\DBAL\\Platforms\\SQLAnywherePlatform\.$/'
|
||||
|
||||
-
|
||||
message: '/^Call to an undefined method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getSQLResultCasing\(\)\.$/'
|
||||
path: src/Internal/SQLResultCasing.php
|
||||
-
|
||||
message: '/^Parameter \$stmt of method .* has invalid type Doctrine\\DBAL\\Driver\\ResultStatement\.$/'
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
-
|
||||
message: '/^Class Doctrine\\DBAL\\Driver\\ResultStatement not found\.$/'
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
-
|
||||
message: '/^Call to static method ensure\(\) on an unknown class Doctrine\\DBAL\\ForwardCompatibility\\Result\.$/'
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
-
|
||||
message: '/^Instanceof between Doctrine\\DBAL\\Platforms\\AbstractPlatform and Doctrine\\DBAL\\Platforms\\MySQLPlatform will always evaluate to false\.$/'
|
||||
path: src/Utility/LockSqlHelper.php
|
||||
|
||||
# Forward compatibility with Collections 3
|
||||
-
|
||||
message: '#^Parameter \$order of anonymous function has invalid type Doctrine\\Common\\Collections\\Order\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
-
|
||||
message: '#^Anonymous function has invalid return type Doctrine\\Common\\Collections\\Order\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
-
|
||||
message: '#^Access to property \$value on an unknown class Doctrine\\Common\\Collections\\Order\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
-
|
||||
message: '#^Call to static method from\(\) on an unknown class Doctrine\\Common\\Collections\\Order\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\Common\\Collections\\Criteria\:\:orderings\(\)\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
-
|
||||
message: '#^Method .+\:\:mapToOrderEnumIfAvailable\(\) has invalid return type Doctrine\\Common\\Collections\\Order\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
# False positive
|
||||
-
|
||||
message: '/^Call to an undefined method Doctrine\\Common\\Cache\\Cache::deleteAll\(\)\.$/'
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/ClearCache/ResultCommand.php
|
||||
|
||||
# Symfony cache supports passing a key prefix to the clear method.
|
||||
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
|
||||
|
||||
-
|
||||
message: '#contains generic type.*but class.*is not generic#'
|
||||
paths:
|
||||
- src/Mapping/Driver/XmlDriver.php
|
||||
- src/Mapping/Driver/YamlDriver.php
|
||||
76
phpstan.neon
76
phpstan.neon
@@ -4,49 +4,49 @@ includes:
|
||||
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
# deprecations from doctrine/dbal:3.x
|
||||
- '/^Call to an undefined method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getGuidExpression\(\).$/'
|
||||
|
||||
# Fallback logic for DBAL 2
|
||||
-
|
||||
message: '/Application::add\(\) expects Symfony\\Component\\Console\\Command\\Command/'
|
||||
path: src/Tools/Console/ConsoleRunner.php
|
||||
|
||||
- '/^Class Doctrine\\DBAL\\Platforms\\SQLAnywherePlatform not found\.$/'
|
||||
- '/^Call to method \w+\(\) on an unknown class Doctrine\\DBAL\\Platforms\\SQLAnywherePlatform\.$/'
|
||||
|
||||
-
|
||||
message: '/^Call to an undefined method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getSQLResultCasing\(\)\.$/'
|
||||
path: src/Internal/SQLResultCasing.php
|
||||
-
|
||||
message: '/^Parameter \$stmt of method .* has invalid type Doctrine\\DBAL\\Driver\\ResultStatement\.$/'
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
-
|
||||
message: '/^Class Doctrine\\DBAL\\Driver\\ResultStatement not found\.$/'
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
-
|
||||
message: '/^Call to static method ensure\(\) on an unknown class Doctrine\\DBAL\\ForwardCompatibility\\Result\.$/'
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
-
|
||||
message: '/^Instanceof between Doctrine\\DBAL\\Platforms\\AbstractPlatform and Doctrine\\DBAL\\Platforms\\MySQLPlatform will always evaluate to false\.$/'
|
||||
path: src/Utility/LockSqlHelper.php
|
||||
|
||||
# False positive
|
||||
-
|
||||
message: '/^Call to an undefined method Doctrine\\Common\\Cache\\Cache::deleteAll\(\)\.$/'
|
||||
count: 1
|
||||
path: src/Tools/Console/Command/ClearCache/ResultCommand.php
|
||||
|
||||
# Symfony cache supports passing a key prefix to the clear method.
|
||||
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
|
||||
|
||||
# Persistence 2 support
|
||||
# We can be certain that those values are not matched.
|
||||
-
|
||||
message: '/clear.*invoked with 1 parameter/'
|
||||
path: src/EntityRepository.php
|
||||
message: '~^Match expression does not handle remaining values:~'
|
||||
path: src/Persisters/Entity/BasicEntityPersister.php
|
||||
|
||||
# DBAL 4 compatibility
|
||||
-
|
||||
message: '#^Class Doctrine\\Persistence\\ObjectManagerAware not found\.$#'
|
||||
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
|
||||
|
||||
# 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: '#^Call to method injectObjectManager\(\) on an unknown class Doctrine\\Persistence\\ObjectManagerAware\.$#'
|
||||
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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user