mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
932 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19912de927 | ||
|
|
737cca5b78 | ||
|
|
9e999ea1ff | ||
|
|
6755bb0c7b | ||
|
|
c2a49327a7 | ||
|
|
9bd7242376 | ||
|
|
fff085b63f | ||
|
|
5ad5b11ae1 | ||
|
|
c12fd2cb94 | ||
|
|
44d5d4a779 | ||
|
|
e3cabade99 | ||
|
|
9402f9e0f7 | ||
|
|
4feaa470af | ||
|
|
4a9101f383 | ||
|
|
f91da5b950 | ||
|
|
66f654d4e2 | ||
|
|
53b51ae40e | ||
|
|
95b0f5c328 | ||
|
|
a5c80a4c75 | ||
|
|
6fd26a3933 | ||
|
|
8ef9253999 | ||
|
|
0ed0be089c | ||
|
|
8fb1043e96 | ||
|
|
fd041fbe80 | ||
|
|
eadf96c879 | ||
|
|
0d770c89d6 | ||
|
|
4bda5147f3 | ||
|
|
38c6569645 | ||
|
|
7c0eebe90a | ||
|
|
8784f2bce9 | ||
|
|
fbcac42ebd | ||
|
|
619302dc9a | ||
|
|
82e2c981da | ||
|
|
8422a41423 | ||
|
|
58ad1d9678 | ||
|
|
346c49832c | ||
|
|
f140651ff0 | ||
|
|
bb5b2a3300 | ||
|
|
ba11851ac4 | ||
|
|
4fbce94999 | ||
|
|
486e406236 | ||
|
|
7d1b24f3b1 | ||
|
|
43ce0bef78 | ||
|
|
d9aa6ef6dc | ||
|
|
ff3ccff36a | ||
|
|
9e2bfa8169 | ||
|
|
3ca9529c32 | ||
|
|
439b4dacf4 | ||
|
|
182469b346 | ||
|
|
e47398ecc5 | ||
|
|
9e884ccf1f | ||
|
|
982d6060a3 | ||
|
|
013f850c76 | ||
|
|
ef4508e52f | ||
|
|
f53350934f | ||
|
|
4ff909044e | ||
|
|
32682aa14d | ||
|
|
bd20df1043 | ||
|
|
2ec2030ab2 | ||
|
|
8ed6c2234a | ||
|
|
ff612b9678 | ||
|
|
ee0d7197dd | ||
|
|
39d2136f46 | ||
|
|
bea454eefc | ||
|
|
14f2572e4e | ||
|
|
c2c500077b | ||
|
|
6281c2b79f | ||
|
|
bac1c17eab | ||
|
|
b6137c8911 | ||
|
|
51be1b1d52 | ||
|
|
488a5dd3bf | ||
|
|
896c65504d | ||
|
|
16a8f10fd2 | ||
|
|
d80a831157 | ||
|
|
52660297ab | ||
|
|
58287bb731 | ||
|
|
bc37f75b41 | ||
|
|
8a25b264f7 | ||
|
|
0e48b19cd3 | ||
|
|
109042e5af | ||
|
|
08328adc6c | ||
|
|
65806884b0 | ||
|
|
ad80e8281a | ||
|
|
0c0c61c51b | ||
|
|
cc28fed9f5 | ||
|
|
2245149588 | ||
|
|
b13564c6c0 | ||
|
|
91709c1275 | ||
|
|
d18126aac5 | ||
|
|
b7fd8241cf | ||
|
|
2432939e4f | ||
|
|
1bf4603422 | ||
|
|
25d5bc5b46 | ||
|
|
6cde337777 | ||
|
|
74ef28295a | ||
|
|
168ac31084 | ||
|
|
fe4a2e83cf | ||
|
|
8ac6a13ca0 | ||
|
|
2707b09a07 | ||
|
|
121158f92c | ||
|
|
51ad860a25 | ||
|
|
9bd51aaeb6 | ||
|
|
c37b115450 | ||
|
|
19129e9f8a | ||
|
|
7d01f19667 | ||
|
|
c1bb2ccf4b | ||
|
|
e3d7c6076c | ||
|
|
40f299f1eb | ||
|
|
d0e9177121 | ||
|
|
68af854f46 | ||
|
|
77467cd824 | ||
|
|
802f20b8e7 | ||
|
|
96d13ac62a | ||
|
|
2ea6a1a5fb | ||
|
|
83851a9716 | ||
|
|
066ec1ac81 | ||
|
|
68744489f0 | ||
|
|
cc2ad1993c | ||
|
|
e4d46c4276 | ||
|
|
858a1adc3b | ||
|
|
3b499132d9 | ||
|
|
39153fd88a | ||
|
|
bdc9679e37 | ||
|
|
87a8ee21c9 | ||
|
|
59c8bc09ab | ||
|
|
3a7d7c9f57 | ||
|
|
06eca40134 | ||
|
|
23b35e9554 | ||
|
|
e063926cbd | ||
|
|
4a01a76a17 | ||
|
|
93c2dd9d4b | ||
|
|
75bc22980e | ||
|
|
9696c3434d | ||
|
|
bf3e082c00 | ||
|
|
d31aabb40c | ||
|
|
d66884403f | ||
|
|
552eae37a3 | ||
|
|
ee4b03aa78 | ||
|
|
eb49f66926 | ||
|
|
73e30df52b | ||
|
|
c5291b4de8 | ||
|
|
831d86548c | ||
|
|
f26b3b9cf9 | ||
|
|
9ab84f7478 | ||
|
|
e6bb4ef20e | ||
|
|
8b6a58fa0e | ||
|
|
94986af284 | ||
|
|
ad5c8e4bdc | ||
|
|
c363f55ad1 | ||
|
|
c973a62272 | ||
|
|
8d3446015a | ||
|
|
4e335f4044 | ||
|
|
bb36d49b38 | ||
|
|
2b81a8e260 | ||
|
|
7d3b3f28e9 | ||
|
|
cbec236e8b | ||
|
|
306963fe79 | ||
|
|
fb4578406f | ||
|
|
bdc41e2b5e | ||
|
|
90376a6431 | ||
|
|
b725908c83 | ||
|
|
b274893486 | ||
|
|
8709fb38b0 | ||
|
|
e9e60f2fbc | ||
|
|
5f3c1dbab8 | ||
|
|
6090141e0b | ||
|
|
e4a6c041b5 | ||
|
|
be307edba8 | ||
|
|
c54c557e02 | ||
|
|
46d0865339 | ||
|
|
1a5a4c674a | ||
|
|
95795c87a8 | ||
|
|
083f642cfa | ||
|
|
db6e702088 | ||
|
|
716da7e538 | ||
|
|
5ccbc201bf | ||
|
|
d15624f72f | ||
|
|
9d1a4973ae | ||
|
|
bcdc5bdaf4 | ||
|
|
40a0964f06 | ||
|
|
08a9e60ed0 | ||
|
|
3e3c023c95 | ||
|
|
5e6d5c06a9 | ||
|
|
1622b7877d | ||
|
|
80aae2796d | ||
|
|
528ef40fc4 | ||
|
|
4b4b9b7b6f | ||
|
|
ae842259f5 | ||
|
|
820a0da4c1 | ||
|
|
fcd02b1ee2 | ||
|
|
a3e3a3bbf3 | ||
|
|
abcad6fa45 | ||
|
|
1b6cf58a1a | ||
|
|
6501890ab5 | ||
|
|
e399d21fb3 | ||
|
|
16f355f0cc | ||
|
|
94d45a036f | ||
|
|
9acca2252f | ||
|
|
a809a71aa6 | ||
|
|
bd4449c462 | ||
|
|
e3e96745cc | ||
|
|
12e0cefba1 | ||
|
|
21221f73cc | ||
|
|
ab5e9e393b | ||
|
|
e62571c8f4 | ||
|
|
98f9de2af6 | ||
|
|
52a6a21387 | ||
|
|
83c81f6c41 | ||
|
|
4fc8629414 | ||
|
|
791667a9e4 | ||
|
|
feb27f00c1 | ||
|
|
abd9186d00 | ||
|
|
719d007a81 | ||
|
|
08d3f72755 | ||
|
|
779781173a | ||
|
|
76c4539ffa | ||
|
|
0f8d193512 | ||
|
|
cc314d0fb7 | ||
|
|
c9c493b2fe | ||
|
|
e6eef1a97d | ||
|
|
8d4718f875 | ||
|
|
c0dfba2ef3 | ||
|
|
0efac09141 | ||
|
|
efb6cebd41 | ||
|
|
e4769d3191 | ||
|
|
cf408ad9ae | ||
|
|
7c29078051 | ||
|
|
b59189ab48 | ||
|
|
401a0c4fe9 | ||
|
|
dba9d72b2d | ||
|
|
fe0647053a | ||
|
|
7b3db4a037 | ||
|
|
e5e3166747 | ||
|
|
afbf293c94 | ||
|
|
1d218bae30 | ||
|
|
7baef1e120 | ||
|
|
5049b615c5 | ||
|
|
40fbbf4429 | ||
|
|
6f98147d09 | ||
|
|
cfadb5499d | ||
|
|
9ce9ae2818 | ||
|
|
fdb9d44538 | ||
|
|
a9fcaf1d18 | ||
|
|
f2176a9ce5 | ||
|
|
9a6ff66c5e | ||
|
|
f58984c43f | ||
|
|
79c7c5087e | ||
|
|
12c4560f1d | ||
|
|
152ebd756c | ||
|
|
8845b6de0f | ||
|
|
e110941f9d | ||
|
|
5b5b56d83a | ||
|
|
a9c45a37ff | ||
|
|
82533af893 | ||
|
|
b988137378 | ||
|
|
ccfc97c32f | ||
|
|
d386b43be3 | ||
|
|
0970ce7072 | ||
|
|
624c56be72 | ||
|
|
020d31efba | ||
|
|
fbc8e6741e | ||
|
|
2d65bc265b | ||
|
|
7151db3cb8 | ||
|
|
c23524259c | ||
|
|
4bddab9e09 | ||
|
|
df730d69b8 | ||
|
|
ac24c11808 | ||
|
|
dd478d8662 | ||
|
|
0b3cd72609 | ||
|
|
85034699cb | ||
|
|
d98186e2c4 | ||
|
|
2b8d6f87b2 | ||
|
|
a0ed37954b | ||
|
|
4875f4c878 | ||
|
|
b648bea2af | ||
|
|
f16594e89c | ||
|
|
398ab0547a | ||
|
|
8f15337b03 | ||
|
|
a8632aca8f | ||
|
|
3dd3d38857 | ||
|
|
c6b3509aa9 | ||
|
|
a32578b7ea | ||
|
|
d6989297c5 | ||
|
|
e585a92763 | ||
|
|
073f2aa891 | ||
|
|
a98e306335 | ||
|
|
26f47cb8d3 | ||
|
|
ebb101009c | ||
|
|
091e43eb9d | ||
|
|
f80ef66ffb | ||
|
|
85d78f8b0d | ||
|
|
c2886478e8 | ||
|
|
108fa30db2 | ||
|
|
9785cb84c6 | ||
|
|
393679a479 | ||
|
|
e50ae06fe7 | ||
|
|
05ef1f4f96 | ||
|
|
2b91edc525 | ||
|
|
6af7f9f7bf | ||
|
|
46cb9a980b | ||
|
|
c2d29d55ab | ||
|
|
ed1df148c2 | ||
|
|
44e943e100 | ||
|
|
23d36c0d52 | ||
|
|
212edaa80b | ||
|
|
e5ab18ff80 | ||
|
|
665ccf1376 | ||
|
|
1a4fe6e0bb | ||
|
|
0a7b939623 | ||
|
|
6be65ebc70 | ||
|
|
e8afa9f80c | ||
|
|
1267f482ef | ||
|
|
b41de2a39d | ||
|
|
6a48b0741b | ||
|
|
0e95838787 | ||
|
|
be62f72b38 | ||
|
|
7613f25d57 | ||
|
|
c075154e1e | ||
|
|
f08159eb87 | ||
|
|
300cffb942 | ||
|
|
2a9390d426 | ||
|
|
ec74c83845 | ||
|
|
4b2b4860fb | ||
|
|
609e10df36 | ||
|
|
d03aed1265 | ||
|
|
6993ad28ed | ||
|
|
16028e4fd3 | ||
|
|
609647a51a | ||
|
|
293299a314 | ||
|
|
0b7fe1862e | ||
|
|
866283d1a7 | ||
|
|
3676e3c571 | ||
|
|
d84f607487 | ||
|
|
edd962e385 | ||
|
|
a33a3813b2 | ||
|
|
bf69d0ac4e | ||
|
|
3f2fa309d4 | ||
|
|
8057b51f85 | ||
|
|
c09660ac50 | ||
|
|
8ec599bb17 | ||
|
|
bf74b434b8 | ||
|
|
cd54c56278 | ||
|
|
76fd34f766 | ||
|
|
1cec0b82bd | ||
|
|
0e74a180c4 | ||
|
|
fdfca0f0e7 | ||
|
|
42af7cabb7 | ||
|
|
c5137da90e | ||
|
|
e89b680a28 | ||
|
|
07b0917505 | ||
|
|
143ee25697 | ||
|
|
52853c2e9c | ||
|
|
40bfe07172 | ||
|
|
6983f48490 | ||
|
|
194f5062bb | ||
|
|
922365d2c5 | ||
|
|
a1e055b608 | ||
|
|
0e3489b240 | ||
|
|
ff28ba8080 | ||
|
|
41410e6be1 | ||
|
|
b9e55bad4d | ||
|
|
47952c3228 | ||
|
|
fdceb82454 | ||
|
|
dc899e26cf | ||
|
|
48edb33b3f | ||
|
|
9c2e49a665 | ||
|
|
8ef5c80148 | ||
|
|
083b1f98c1 | ||
|
|
3ff67c3e2f | ||
|
|
84a762e12e | ||
|
|
ef2123bd0f | ||
|
|
55699a9129 | ||
|
|
68fc3b6458 | ||
|
|
32192c7b01 | ||
|
|
77843e45f3 | ||
|
|
1919eea0a9 | ||
|
|
925631878f | ||
|
|
db2791001c | ||
|
|
62ed63bbbe | ||
|
|
081ec2ad26 | ||
|
|
633ce41460 | ||
|
|
e9537f4cde | ||
|
|
0f67ba2176 | ||
|
|
38ad3925e2 | ||
|
|
858b01f85e | ||
|
|
9f555ea8fb | ||
|
|
1f8c02f345 | ||
|
|
d81afdb6e3 | ||
|
|
0628204b43 | ||
|
|
816ecc6d6b | ||
|
|
f66263d859 | ||
|
|
8aa5aa2f57 | ||
|
|
96e31a3b30 | ||
|
|
a60a273423 | ||
|
|
a2d2e173c2 | ||
|
|
17500f56ea | ||
|
|
fc2f724e2d | ||
|
|
7986fc64dd | ||
|
|
2f9e98754b | ||
|
|
aa333e2f1d | ||
|
|
b6441b4f26 | ||
|
|
bb5524099c | ||
|
|
3a8cafe228 | ||
|
|
8259a16681 | ||
|
|
5577d51c44 | ||
|
|
d1922a3065 | ||
|
|
9647d0e2ae | ||
|
|
597a63a86c | ||
|
|
368eb01ac3 | ||
|
|
6b220e3c90 | ||
|
|
6de4b68705 | ||
|
|
16c0151831 | ||
|
|
440b244ebc | ||
|
|
47cf50bcd5 | ||
|
|
58df4078fc | ||
|
|
eda1909c75 | ||
|
|
a616914887 | ||
|
|
fd0bdc69b0 | ||
|
|
f50803ccb9 | ||
|
|
eeefc6bc0f | ||
|
|
710dde83aa | ||
|
|
ab542e97df | ||
|
|
495cd06b9a | ||
|
|
fd7a14ad22 | ||
|
|
0d3ce5d4f8 | ||
|
|
f01d107edc | ||
|
|
3cc30c4024 | ||
|
|
d2de4ec03c | ||
|
|
64ee76e94e | ||
|
|
8e20e1598e | ||
|
|
24df74d61d | ||
|
|
442f073d25 | ||
|
|
a5161e9485 | ||
|
|
ddc7d953b9 | ||
|
|
db51ed4f4c | ||
|
|
6d27797b2e | ||
|
|
89250b8ca2 | ||
|
|
f7e4b61459 | ||
|
|
6b0afdbd58 | ||
|
|
d3cf17b26d | ||
|
|
bc61d7d21e | ||
|
|
5213228a64 | ||
|
|
dca7ddf969 | ||
|
|
e781639812 | ||
|
|
7848417488 | ||
|
|
56e5856ad7 | ||
|
|
b5987ad29a | ||
|
|
385bdd33f1 | ||
|
|
8c513a6523 | ||
|
|
1413b496d7 | ||
|
|
3b3056f910 | ||
|
|
fa5c37e972 | ||
|
|
f3e36debfe | ||
|
|
ca7abd04a2 | ||
|
|
a555626150 | ||
|
|
ec7a8a7a0f | ||
|
|
e94fa8588d | ||
|
|
f26946b477 | ||
|
|
efc83bce8e | ||
|
|
450cae2caa | ||
|
|
81ddeb426c | ||
|
|
42e63bf358 | ||
|
|
4978e0e336 | ||
|
|
eee87c376d | ||
|
|
0b9060c728 | ||
|
|
514f6b8c28 | ||
|
|
c1018fe299 | ||
|
|
075824f5b5 | ||
|
|
d6f4834476 | ||
|
|
9dadffe270 | ||
|
|
b6e7e6d723 | ||
|
|
710937d6f8 | ||
|
|
5d2d6642c8 | ||
|
|
4d56711d8c | ||
|
|
a157bc3fb3 | ||
|
|
1aeab391c7 | ||
|
|
a4ecd02349 | ||
|
|
bb21865cba | ||
|
|
606da9280d | ||
|
|
21708e43c4 | ||
|
|
8c59828f6c | ||
|
|
0877ecbe56 | ||
|
|
8eb69922e6 | ||
|
|
e9b6fd89a4 | ||
|
|
01a14327d2 | ||
|
|
4887359827 | ||
|
|
2df1071e7a | ||
|
|
5afe9b80a8 | ||
|
|
7fc359c2bb | ||
|
|
853b9f75ae | ||
|
|
584c4aeed1 | ||
|
|
44d2a83e09 | ||
|
|
c9c5157fda | ||
|
|
dba90c1a91 | ||
|
|
5f079c2061 | ||
|
|
55d477dc50 | ||
|
|
4da8d3be96 | ||
|
|
4aadba65ce | ||
|
|
814d8d4d39 | ||
|
|
dc411954ad | ||
|
|
da29eb675c | ||
|
|
b17e52ba6b | ||
|
|
7ef4afc688 | ||
|
|
4e138903d0 | ||
|
|
efb50b9bdd | ||
|
|
70bcff7410 | ||
|
|
1989531d4f | ||
|
|
f778d8cf98 | ||
|
|
18b32ab9db | ||
|
|
d738ecfcfe | ||
|
|
aa3ff458c7 | ||
|
|
f76bab2b73 | ||
|
|
0e06d6b67d | ||
|
|
5114dcee0b | ||
|
|
8bc74c624a | ||
|
|
6c0a5ecbf9 | ||
|
|
5f6501f842 | ||
|
|
4c3bd20801 | ||
|
|
f2abf6143b | ||
|
|
338deacb58 | ||
|
|
829d5fbb9f | ||
|
|
d220494edc | ||
|
|
c235901544 | ||
|
|
ba089e551a | ||
|
|
ee0b3f214d | ||
|
|
930fa831b2 | ||
|
|
98b404875f | ||
|
|
fcc5c106b4 | ||
|
|
5132f0deb0 | ||
|
|
fe8e313731 | ||
|
|
41f704cd96 | ||
|
|
1adb5c0c70 | ||
|
|
e5174af669 | ||
|
|
c3106f9fe7 | ||
|
|
cbf45dd97e | ||
|
|
3c0d140e52 | ||
|
|
33675ff4a9 | ||
|
|
5c74795893 | ||
|
|
3827dd769e | ||
|
|
6c9b29f237 | ||
|
|
2afe2dc8af | ||
|
|
cc3d872b95 | ||
|
|
8961bfe90c | ||
|
|
15e3a7e861 | ||
|
|
65dc154ce5 | ||
|
|
1280e005b6 | ||
|
|
79f53d5dae | ||
|
|
caaa0d6192 | ||
|
|
68d3a63957 | ||
|
|
bf2937e63a | ||
|
|
76b8a215c2 | ||
|
|
b163cea61c | ||
|
|
ed212ab924 | ||
|
|
dd0e02e912 | ||
|
|
aad875eea1 | ||
|
|
84ab535e56 | ||
|
|
a72a0c3597 | ||
|
|
6217285544 | ||
|
|
330c0bc67e | ||
|
|
b5595ca041 | ||
|
|
4dfbe13897 | ||
|
|
b64e1c9b1f | ||
|
|
b779b112f3 | ||
|
|
bf449bef7d | ||
|
|
152f91fa33 | ||
|
|
14d1eb5340 | ||
|
|
04e08640fb | ||
|
|
aa27b3a35f | ||
|
|
d76fc4ebf6 | ||
|
|
da0998c401 | ||
|
|
ae60cf005f | ||
|
|
ddd3066bc4 | ||
|
|
6662195936 | ||
|
|
cc011d8215 | ||
|
|
d831c126c9 | ||
|
|
10eae1a7ff | ||
|
|
d951aa05b9 | ||
|
|
be297b9fd3 | ||
|
|
125e18cf24 | ||
|
|
8fba9d6868 | ||
|
|
7f4f1cda71 | ||
|
|
4e137f77a5 | ||
|
|
a33aa15c79 | ||
|
|
255ce51526 | ||
|
|
1c905b0e0a | ||
|
|
7901790b97 | ||
|
|
cef1d2d740 | ||
|
|
8126882305 | ||
|
|
a9513692cb | ||
|
|
52c3d9d82a | ||
|
|
2f46e5a130 | ||
|
|
a3fa1d7faa | ||
|
|
c7c57be0c2 | ||
|
|
721794fb9c | ||
|
|
38e47fdeab | ||
|
|
9ac063d879 | ||
|
|
b52a8f8b9e | ||
|
|
70477d81e9 | ||
|
|
1b2771f964 | ||
|
|
9bc6f5b4ac | ||
|
|
9766b6b03e | ||
|
|
37c8953015 | ||
|
|
60c625be17 | ||
|
|
8b0d6a13c2 | ||
|
|
a7ac6ff8d9 | ||
|
|
222d544b0c | ||
|
|
a199ca3002 | ||
|
|
6f1fd7a81e | ||
|
|
2af6e4db38 | ||
|
|
b48dafded8 | ||
|
|
ffe1550a68 | ||
|
|
eef5a1db81 | ||
|
|
c2d053d185 | ||
|
|
77822d623e | ||
|
|
7b5fafffbe | ||
|
|
aba8d74017 | ||
|
|
a056552db9 | ||
|
|
1142a396d3 | ||
|
|
f01b7d254d | ||
|
|
ed34327941 | ||
|
|
1ea8424e07 | ||
|
|
b42cf99402 | ||
|
|
ba9f51a363 | ||
|
|
1ae74b8ec5 | ||
|
|
a64f315dfe | ||
|
|
6ca319a6f4 | ||
|
|
fceb279947 | ||
|
|
2977933119 | ||
|
|
5ac6fadf29 | ||
|
|
e59ed88251 | ||
|
|
a16aeaeac8 | ||
|
|
fca1ef78a7 | ||
|
|
a78e5bcf65 | ||
|
|
09b4a75ed3 | ||
|
|
b984b567b8 | ||
|
|
92c56164ee | ||
|
|
b2707509fc | ||
|
|
1d02139d2a | ||
|
|
e5fb1a4a8f | ||
|
|
8cb7a5e212 | ||
|
|
7ed28dba50 | ||
|
|
f215515bab | ||
|
|
ffbfbfcda1 | ||
|
|
4a30f622ec | ||
|
|
aec3556502 | ||
|
|
33a19f1bf3 | ||
|
|
b6669746b7 | ||
|
|
da9b9de590 | ||
|
|
9ec697db7d | ||
|
|
25bd41a504 | ||
|
|
a50a611bee | ||
|
|
abb30093ed | ||
|
|
df559d8ac0 | ||
|
|
a6de4b9663 | ||
|
|
6db296cd5c | ||
|
|
7c2adde6f2 | ||
|
|
04573fc283 | ||
|
|
82362ee65e | ||
|
|
69543ba1bf | ||
|
|
9ff0440aac | ||
|
|
a33885575f | ||
|
|
e28dee0742 | ||
|
|
2c40e917c8 | ||
|
|
5c06d46874 | ||
|
|
24c4ac4dd8 | ||
|
|
4fad7a1190 | ||
|
|
f36a8c879c | ||
|
|
a28e2d8277 | ||
|
|
fa4b945b94 | ||
|
|
4759a1bf75 | ||
|
|
e0ad7ac506 | ||
|
|
9485d4d835 | ||
|
|
7814cbf4ec | ||
|
|
9a6e1b3505 | ||
|
|
c286742814 | ||
|
|
052887765b | ||
|
|
5464e21022 | ||
|
|
c26c55926f | ||
|
|
5369e4f425 | ||
|
|
29bc6cc955 | ||
|
|
979b3dcb8d | ||
|
|
8efdcb0555 | ||
|
|
3810a0b6f9 | ||
|
|
c9b644dced | ||
|
|
ae6de13c01 | ||
|
|
31ff969628 | ||
|
|
072c40357f | ||
|
|
ca94e82828 | ||
|
|
db0b9d13c6 | ||
|
|
01f139d76c | ||
|
|
660197ea71 | ||
|
|
ab06e07b53 | ||
|
|
022b945ed5 | ||
|
|
7203d05539 | ||
|
|
6c17e47624 | ||
|
|
0bd5fbf215 | ||
|
|
6a713dd39e | ||
|
|
5f169d9325 | ||
|
|
cf4680d0e6 | ||
|
|
cc5775c3f4 | ||
|
|
c5cf6a046b | ||
|
|
77df5db3b9 | ||
|
|
ee8269ea55 | ||
|
|
d038f23570 | ||
|
|
83d56d75e1 | ||
|
|
3843d7e0cc | ||
|
|
d50ba2e248 | ||
|
|
8debb92d78 | ||
|
|
8ff7938e31 | ||
|
|
d593c33ffa | ||
|
|
6c925f5b60 | ||
|
|
82bf68d482 | ||
|
|
d6c0031d44 | ||
|
|
2ee936acb4 | ||
|
|
c78f933e57 | ||
|
|
843bff4971 | ||
|
|
d679292861 | ||
|
|
65687821a7 | ||
|
|
80eb85beaa | ||
|
|
ca0dffb53e | ||
|
|
01028cf3b8 | ||
|
|
84bfe7cbb9 | ||
|
|
1b3978e8c9 | ||
|
|
ed56f42cd5 | ||
|
|
8b28543939 | ||
|
|
eec3c42494 | ||
|
|
7f783b59c8 | ||
|
|
68662f5920 | ||
|
|
769b161dff | ||
|
|
bc394877bc | ||
|
|
1753d03500 | ||
|
|
9857cf971b | ||
|
|
f73dae9bc4 | ||
|
|
1c357b9fb3 | ||
|
|
3d031ed541 | ||
|
|
15ed97b7b1 | ||
|
|
9fd4af23e1 | ||
|
|
7ce6d8d427 | ||
|
|
a48d95c71d | ||
|
|
aee1d33042 | ||
|
|
8da741ad75 | ||
|
|
4206f01e7b | ||
|
|
7d4052c9e7 | ||
|
|
fc6feb5938 | ||
|
|
89b98bdff9 | ||
|
|
ba7387fd8c | ||
|
|
a83e4f7978 | ||
|
|
4f335ab565 | ||
|
|
f88b0032ad | ||
|
|
69c7791ba2 | ||
|
|
1090dbe9be | ||
|
|
c46b604ed7 | ||
|
|
8d9ebeded8 | ||
|
|
55f9178e84 | ||
|
|
37572802cc | ||
|
|
60955755e0 | ||
|
|
a5bdc619c7 | ||
|
|
a8e979819a | ||
|
|
4e8e3ef30b | ||
|
|
65a7c8882f | ||
|
|
2d6295c9db | ||
|
|
de7eee5ed7 | ||
|
|
4051937fda | ||
|
|
b2e42dc92d | ||
|
|
f0616626e0 | ||
|
|
f219b87870 | ||
|
|
a8ef69dbe6 | ||
|
|
c0a7317e8d | ||
|
|
843b0fcc16 | ||
|
|
b56de5b0e2 | ||
|
|
87fefbac34 | ||
|
|
0b35e637b8 | ||
|
|
853e80ca98 | ||
|
|
d68baef880 | ||
|
|
fdccfbd120 | ||
|
|
277614d9c2 | ||
|
|
180afa8c8f | ||
|
|
dbbf5c7279 | ||
|
|
5d9b8f0ea8 | ||
|
|
174947155d | ||
|
|
2138cc9383 | ||
|
|
39a434914d | ||
|
|
227f60c832 | ||
|
|
f72f6b199b | ||
|
|
92e63ca4f9 | ||
|
|
3c98973ab3 | ||
|
|
3b8692fa4a | ||
|
|
c9efc1cdee | ||
|
|
29b8b0bffb | ||
|
|
b7ba018f0a | ||
|
|
c5e4e41e05 | ||
|
|
9431b2ea45 | ||
|
|
72b1bf0c02 | ||
|
|
036ea713a5 | ||
|
|
70241d3407 | ||
|
|
0852847659 | ||
|
|
1d5d47964c | ||
|
|
1e2625a82f | ||
|
|
c9c4203a1e | ||
|
|
3010fd1680 | ||
|
|
091da8c420 | ||
|
|
515a3d8b8b | ||
|
|
85ac2769a9 | ||
|
|
28e98b3475 | ||
|
|
99a37d864e | ||
|
|
603ab9a185 | ||
|
|
10d27c18ea | ||
|
|
ae9fb8ca21 | ||
|
|
c7f2a1d580 | ||
|
|
27df173971 | ||
|
|
0aa45dd607 | ||
|
|
b3f441cb8b | ||
|
|
f8bf84d1aa | ||
|
|
c825e34f8d | ||
|
|
ff6bad486b | ||
|
|
30a2680bfd | ||
|
|
a460a4d054 | ||
|
|
f82485e651 | ||
|
|
c4835cca0d | ||
|
|
82a406332e | ||
|
|
8093c2eef6 | ||
|
|
f94cb9a5e6 | ||
|
|
6255461b84 | ||
|
|
0aa5946286 | ||
|
|
eda7558674 | ||
|
|
13bab31da6 | ||
|
|
f960bc2c11 | ||
|
|
15058ca83e | ||
|
|
9b14786738 | ||
|
|
497ee166bd | ||
|
|
db18161a1a | ||
|
|
284e81403b | ||
|
|
3ea8550ca6 | ||
|
|
aa4b62ce78 | ||
|
|
e5e674c686 | ||
|
|
9d5ab4ce76 | ||
|
|
a2b5bae923 | ||
|
|
5a8541b450 | ||
|
|
fa18e130cb | ||
|
|
24bf06725b | ||
|
|
d5ef6be4cc | ||
|
|
54336840e6 | ||
|
|
74986f1d53 | ||
|
|
16cd49ba89 | ||
|
|
f9d5a89a39 | ||
|
|
db7333cc84 | ||
|
|
47b4ccc4e6 | ||
|
|
5a7fce12b8 | ||
|
|
cc9e456ed8 | ||
|
|
da356316c1 | ||
|
|
1ce806fcb7 | ||
|
|
958d0b6193 | ||
|
|
843f3c3b23 | ||
|
|
82e4c644f9 | ||
|
|
9399f1f3a8 | ||
|
|
ad69810775 | ||
|
|
6c7a5e6faa | ||
|
|
dcc1c26826 | ||
|
|
8afb644a18 | ||
|
|
953e42d059 | ||
|
|
318af0a666 | ||
|
|
90ececcc85 | ||
|
|
88b36e07e1 | ||
|
|
a37c2cc05f | ||
|
|
40b34b03c1 | ||
|
|
8d9ab72613 | ||
|
|
12f0674b1a | ||
|
|
069206ba14 | ||
|
|
e8a4d2e91b | ||
|
|
284baf890e | ||
|
|
a1f9b28cdc | ||
|
|
2b7485af97 | ||
|
|
edb6332359 | ||
|
|
48c1eef1b8 | ||
|
|
5d88dc9be4 | ||
|
|
c97f0a1078 | ||
|
|
474f76fc8b | ||
|
|
25ce9b9101 | ||
|
|
75340b68b2 | ||
|
|
543be3fe35 | ||
|
|
1edfa91714 | ||
|
|
c828a3814b | ||
|
|
cf91ce63d3 | ||
|
|
f3f453286f | ||
|
|
7cb96fcf0e | ||
|
|
ac94d826dc | ||
|
|
f33919d7d6 | ||
|
|
f256d996cc | ||
|
|
d617323a48 | ||
|
|
6b61e26238 | ||
|
|
edad800711 | ||
|
|
fba05675b6 | ||
|
|
8160e89c5a | ||
|
|
a76b776802 | ||
|
|
ad1d1ca942 | ||
|
|
be835bb8e2 | ||
|
|
bac784c9ba | ||
|
|
1ad936a448 | ||
|
|
7e75807918 | ||
|
|
90f82202a8 | ||
|
|
97aa5b37e6 | ||
|
|
1a9f40c785 | ||
|
|
7ce9a6fe5c | ||
|
|
8e062955d5 | ||
|
|
0e65b0c3dc | ||
|
|
e14e9bebcc | ||
|
|
9422260efd | ||
|
|
d46512332c | ||
|
|
0d56ffc261 | ||
|
|
95c818928e | ||
|
|
f27034880a | ||
|
|
3735822662 | ||
|
|
52f7ddc680 | ||
|
|
de32d8239f | ||
|
|
397751ee65 | ||
|
|
b0038eeea6 | ||
|
|
f06f9f843e | ||
|
|
5d3fc62023 | ||
|
|
154e7130f5 | ||
|
|
99f044cbc7 | ||
|
|
e8ca7b4abf | ||
|
|
b05fb96ad3 | ||
|
|
bb020320ca | ||
|
|
1e0ac8899c | ||
|
|
4a04c8c2db | ||
|
|
470e2ddd05 | ||
|
|
6ec5ab9145 | ||
|
|
86000d9c70 | ||
|
|
328bf707cc | ||
|
|
7a9037e9d7 | ||
|
|
8d03f8f089 | ||
|
|
8dfe8b8782 |
@@ -6,26 +6,76 @@
|
||||
"docsSlug": "doctrine-orm",
|
||||
"versions": [
|
||||
{
|
||||
"name": "3.0",
|
||||
"branchName": "3.0.x",
|
||||
"name": "4.0",
|
||||
"branchName": "4.0.x",
|
||||
"slug": "latest",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "3.2",
|
||||
"branchName": "3.2.x",
|
||||
"slug": "3.2",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "3.1",
|
||||
"branchName": "3.1.x",
|
||||
"slug": "3.1",
|
||||
"current": true
|
||||
},
|
||||
{
|
||||
"name": "3.0",
|
||||
"branchName": "3.0.x",
|
||||
"slug": "3.0",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"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.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",
|
||||
"upcoming": true
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.13",
|
||||
"branchName": "2.13.x",
|
||||
"slug": "2.13",
|
||||
"current": true,
|
||||
"aliases": [
|
||||
"current",
|
||||
"stable"
|
||||
]
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.12",
|
||||
|
||||
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
|
||||
|
||||
6
.github/workflows/coding-standards.yml
vendored
6
.github/workflows/coding-standards.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
- .github/workflows/coding-standards.yml
|
||||
- bin/**
|
||||
- composer.*
|
||||
- lib/**
|
||||
- src/**
|
||||
- phpcs.xml.dist
|
||||
- tests/**
|
||||
push:
|
||||
@@ -18,10 +18,10 @@ on:
|
||||
- .github/workflows/coding-standards.yml
|
||||
- bin/**
|
||||
- composer.*
|
||||
- lib/**
|
||||
- src/**
|
||||
- phpcs.xml.dist
|
||||
- tests/**
|
||||
|
||||
jobs:
|
||||
coding-standards:
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@3.0.0"
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.2.1"
|
||||
|
||||
78
.github/workflows/continuous-integration.yml
vendored
78
.github/workflows/continuous-integration.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
- .github/workflows/continuous-integration.yml
|
||||
- ci/**
|
||||
- composer.*
|
||||
- lib/**
|
||||
- src/**
|
||||
- phpunit.xml.dist
|
||||
- tests/**
|
||||
push:
|
||||
@@ -18,7 +18,7 @@ on:
|
||||
- .github/workflows/continuous-integration.yml
|
||||
- ci/**
|
||||
- composer.*
|
||||
- lib/**
|
||||
- src/**
|
||||
- phpunit.xml.dist
|
||||
- tests/**
|
||||
|
||||
@@ -39,10 +39,14 @@ jobs:
|
||||
- "8.0"
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
extension:
|
||||
- "pdo_sqlite"
|
||||
proxy:
|
||||
- "common"
|
||||
include:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
@@ -53,10 +57,14 @@ jobs:
|
||||
- php-version: "8.2"
|
||||
dbal-version: "default"
|
||||
extension: "sqlite3"
|
||||
- php-version: "8.1"
|
||||
dbal-version: "default"
|
||||
proxy: "lazy-ghost"
|
||||
extension: "pdo_sqlite"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -73,7 +81,7 @@ jobs:
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -81,16 +89,18 @@ jobs:
|
||||
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 }}"
|
||||
|
||||
- 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 }}"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v3"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.proxy }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
|
||||
|
||||
@@ -103,18 +113,25 @@ jobs:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
postgres-version:
|
||||
- "15"
|
||||
- "17"
|
||||
extension:
|
||||
- pdo_pgsql
|
||||
- pgsql
|
||||
include:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
postgres-version: "14"
|
||||
extension: pdo_pgsql
|
||||
- php-version: "8.2"
|
||||
dbal-version: "default"
|
||||
postgres-version: "9.6"
|
||||
extension: pdo_pgsql
|
||||
|
||||
services:
|
||||
postgres:
|
||||
@@ -130,7 +147,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -138,6 +155,7 @@ jobs:
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
extensions: "pgsql pdo_pgsql"
|
||||
coverage: "pcov"
|
||||
ini-values: "zend.assertions=1, apc.enable_cli=1"
|
||||
|
||||
@@ -146,7 +164,7 @@ jobs:
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -154,9 +172,9 @@ jobs:
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v3"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.extension }}-coverage"
|
||||
path: "coverage.xml"
|
||||
|
||||
|
||||
@@ -169,11 +187,13 @@ jobs:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
mariadb-version:
|
||||
- "10.9"
|
||||
- "11.4"
|
||||
extension:
|
||||
- "mysqli"
|
||||
- "pdo_mysql"
|
||||
@@ -187,18 +207,18 @@ jobs:
|
||||
mariadb:
|
||||
image: "mariadb:${{ matrix.mariadb-version }}"
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: "doctrine_tests"
|
||||
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: yes
|
||||
MARIADB_DATABASE: "doctrine_tests"
|
||||
|
||||
options: >-
|
||||
--health-cmd "mysqladmin ping --silent"
|
||||
--health-cmd "healthcheck.sh --connect --innodb_initialized"
|
||||
|
||||
ports:
|
||||
- "3306:3306"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -215,7 +235,7 @@ jobs:
|
||||
extensions: "${{ matrix.extension }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -223,7 +243,7 @@ jobs:
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v3"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage.xml"
|
||||
@@ -238,6 +258,8 @@ jobs:
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -267,7 +289,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -284,7 +306,7 @@ jobs:
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -299,7 +321,7 @@ jobs:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 1
|
||||
|
||||
- name: "Upload coverage files"
|
||||
uses: "actions/upload-artifact@v3"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
@@ -319,7 +341,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -330,7 +352,7 @@ jobs:
|
||||
ini-values: "zend.assertions=1, apc.enable_cli=1"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "${{ matrix.deps }}"
|
||||
|
||||
@@ -341,6 +363,8 @@ jobs:
|
||||
upload_coverage:
|
||||
name: "Upload coverage to Codecov"
|
||||
runs-on: "ubuntu-22.04"
|
||||
# Only run on PRs from forks
|
||||
if: "github.event.pull_request.head.repo.full_name != github.repository"
|
||||
needs:
|
||||
- "phpunit-smoke-check"
|
||||
- "phpunit-postgres"
|
||||
@@ -349,16 +373,18 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: "Download coverage files"
|
||||
uses: "actions/download-artifact@v3"
|
||||
uses: "actions/download-artifact@v4"
|
||||
with:
|
||||
path: "reports"
|
||||
|
||||
- name: "Upload to Codecov"
|
||||
uses: "codecov/codecov-action@v3"
|
||||
uses: "codecov/codecov-action@v5"
|
||||
with:
|
||||
directory: reports
|
||||
env:
|
||||
CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
|
||||
|
||||
20
.github/workflows/documentation.yml
vendored
Normal file
20
.github/workflows/documentation.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: "Documentation"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- ".github/workflows/documentation.yml"
|
||||
- "docs/**"
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- ".github/workflows/documentation.yml"
|
||||
- "docs/**"
|
||||
|
||||
jobs:
|
||||
documentation:
|
||||
name: "Documentation"
|
||||
uses: "doctrine/.github/.github/workflows/documentation.yml@7.2.1"
|
||||
17
.github/workflows/phpbench.yml
vendored
17
.github/workflows/phpbench.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
paths:
|
||||
- .github/workflows/phpbench.yml
|
||||
- composer.*
|
||||
- lib/**
|
||||
- src/**
|
||||
- phpbench.json
|
||||
- tests/**
|
||||
push:
|
||||
@@ -17,7 +17,7 @@ on:
|
||||
paths:
|
||||
- .github/workflows/phpbench.yml
|
||||
- composer.*
|
||||
- lib/**
|
||||
- src/**
|
||||
- phpbench.json
|
||||
- tests/**
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -47,15 +47,8 @@ jobs:
|
||||
coverage: "pcov"
|
||||
ini-values: "zend.assertions=1, apc.enable_cli=1"
|
||||
|
||||
- name: "Cache dependencies installed with composer"
|
||||
uses: "actions/cache@v3"
|
||||
with:
|
||||
path: "~/.composer/cache"
|
||||
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
|
||||
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: "composer update --no-interaction --no-progress"
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
|
||||
- name: "Run PHPBench"
|
||||
run: "vendor/bin/phpbench run --report=default"
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@3.0.0"
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.2.1"
|
||||
secrets:
|
||||
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
|
||||
44
.github/workflows/static-analysis.yml
vendored
44
.github/workflows/static-analysis.yml
vendored
@@ -7,20 +7,18 @@ on:
|
||||
paths:
|
||||
- .github/workflows/static-analysis.yml
|
||||
- composer.*
|
||||
- lib/**
|
||||
- src/**
|
||||
- phpstan*
|
||||
- psalm*
|
||||
- tests/Doctrine/StaticAnalysis/**
|
||||
- tests/StaticAnalysis/**
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/static-analysis.yml
|
||||
- composer.*
|
||||
- lib/**
|
||||
- src/**
|
||||
- phpstan*
|
||||
- psalm*
|
||||
- tests/Doctrine/StaticAnalysis/**
|
||||
- tests/StaticAnalysis/**
|
||||
|
||||
jobs:
|
||||
static-analysis-phpstan:
|
||||
@@ -42,24 +40,23 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.2"
|
||||
php-version: "8.4"
|
||||
|
||||
- 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 }} --no-update"
|
||||
if: "${{ matrix.persistence-version != 'default' }}"
|
||||
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@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
@@ -74,28 +71,3 @@ jobs:
|
||||
- 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@v3"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.2"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
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)"
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,9 +3,6 @@ logs/
|
||||
reports/
|
||||
dist/
|
||||
download/
|
||||
lib/api/
|
||||
lib/Doctrine/Common
|
||||
lib/Doctrine/DBAL
|
||||
/.settings/
|
||||
.buildpath
|
||||
.project
|
||||
@@ -15,5 +12,6 @@ vendor/
|
||||
/tests/Doctrine/Performance/history.db
|
||||
/.phpcs-cache
|
||||
composer.lock
|
||||
.phpunit.cache
|
||||
.phpunit.result.cache
|
||||
/*.phpunit.xml
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,6 +0,0 @@
|
||||
[submodule "docs/en/_theme"]
|
||||
path = docs/en/_theme
|
||||
url = git://github.com/doctrine/doctrine-sphinx-theme.git
|
||||
[submodule "lib/vendor/doctrine-build-common"]
|
||||
path = lib/vendor/doctrine-build-common
|
||||
url = git://github.com/doctrine/doctrine-build-common.git
|
||||
@@ -23,7 +23,7 @@ You may fix many some of the issues with `vendor/bin/phpcbf`.
|
||||
Please try to add a test for your pull-request.
|
||||
|
||||
* If you want to fix a bug or provide a reproduce case, create a test file in
|
||||
``tests/Doctrine/Tests/ORM/Functional/Ticket`` with the name of the ticket,
|
||||
``tests/Tests/ORM/Functional/Ticket`` with the name of the ticket,
|
||||
``DDC1234Test.php`` for example.
|
||||
* If you want to contribute new functionality add unit- or functional tests
|
||||
depending on the scope of the feature.
|
||||
@@ -40,6 +40,11 @@ cd orm
|
||||
composer install
|
||||
```
|
||||
|
||||
You will also need to enable the PHP extension that provides the SQLite driver
|
||||
for PDO: `pdo_sqlite`. How to do so depends on your system, but checking that it
|
||||
is enabled can universally be done with `php -m`: that command should list the
|
||||
extension.
|
||||
|
||||
To run the testsuite against another database, copy the ``phpunit.xml.dist``
|
||||
to for example ``mysql.phpunit.xml`` and edit the parameters. You can
|
||||
take a look at the ``ci/github/phpunit`` directory for some examples. Then run:
|
||||
@@ -52,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/Doctrine/Tests/ORM/Functional/Ticket/DDC2306Test.php` for an
|
||||
See `https://github.com/doctrine/orm/tree/2.8.x/tests/Tests/ORM/Functional/Ticket/DDC2306Test.php` for an
|
||||
example.
|
||||
|
||||
## Getting merged
|
||||
|
||||
40
README.md
40
README.md
@@ -1,7 +1,7 @@
|
||||
| [3.0.x][3.0] | [2.14.x][2.14] | [2.13.x][2.13] |
|
||||
|:----------------:|:----------------:|:----------:|
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.14 image]][2.14] | [![Build status][2.13 image]][2.13] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.14 coverage image]][2.14 coverage] | [![Coverage Status][2.13 coverage image]][2.13 coverage] |
|
||||
| [4.0.x][4.0] | [3.4.x][3.4] | [3.3.x][3.3] | [2.21.x][2.21] | [2.20.x][2.20] |
|
||||
|:------------------------------------------------------:|:------------------------------------------------------:|:------------------------------------------------------:|:--------------------------------------------------------:|:--------------------------------------------------------:|
|
||||
| [![Build status][4.0 image]][4.0] | [![Build status][3.4 image]][3.4] | [![Build status][3.3 image]][3.3] | [![Build status][2.21 image]][2.21] | [![Build status][2.20 image]][2.20] |
|
||||
| [![Coverage Status][4.0 coverage image]][4.0 coverage] | [![Coverage Status][3.4 coverage image]][3.4 coverage] | [![Coverage Status][3.3 coverage image]][3.3 coverage] | [![Coverage Status][2.21 coverage image]][2.21 coverage] | [![Coverage Status][2.20 coverage image]][2.20 coverage] |
|
||||
|
||||
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
|
||||
|
||||
@@ -18,15 +18,23 @@ without requiring unnecessary code duplication.
|
||||
* [Documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/stable/index.html)
|
||||
|
||||
|
||||
[3.0 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.0.x
|
||||
[3.0]: https://github.com/doctrine/orm/tree/3.0.x
|
||||
[3.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.0.x/graph/badge.svg
|
||||
[3.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.0.x
|
||||
[2.14 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.14.x
|
||||
[2.14]: https://github.com/doctrine/orm/tree/2.14.x
|
||||
[2.14 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.14.x/graph/badge.svg
|
||||
[2.14 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.14.x
|
||||
[2.13 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.13.x
|
||||
[2.13]: https://github.com/doctrine/orm/tree/2.13.x
|
||||
[2.13 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.13.x/graph/badge.svg
|
||||
[2.13 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.13.x
|
||||
[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 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.4 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.4.x
|
||||
[3.4]: https://github.com/doctrine/orm/tree/3.4.x
|
||||
[3.4 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.4.x/graph/badge.svg
|
||||
[3.4 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.4.x
|
||||
[3.3 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.3.x
|
||||
[3.3]: https://github.com/doctrine/orm/tree/3.3.x
|
||||
[3.3 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.3.x/graph/badge.svg
|
||||
[3.3 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.3.x
|
||||
[2.21 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.21.x
|
||||
[2.21]: https://github.com/doctrine/orm/tree/2.21.x
|
||||
[2.21 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.21.x/graph/badge.svg
|
||||
[2.21 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.21.x
|
||||
[2.20 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.20.x
|
||||
[2.20]: https://github.com/doctrine/orm/tree/2.20.x
|
||||
[2.20 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.20.x/graph/badge.svg
|
||||
[2.20 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.20.x
|
||||
|
||||
@@ -13,6 +13,5 @@ understand the assumptions we make.
|
||||
- [DBAL Security Page](https://www.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/security.html)
|
||||
- [ORM Security Page](https://www.doctrine-project.org/projects/doctrine-orm/en/stable/reference/security.html)
|
||||
|
||||
If you find a Security bug in Doctrine, please report it on Jira and change the
|
||||
Security Level to "Security Issues". It will be visible to Doctrine Core
|
||||
developers and you only.
|
||||
If you find a Security bug in Doctrine, please follow our
|
||||
[Security reporting guidelines](https://www.doctrine-project.org/policies/security.html#reporting).
|
||||
|
||||
291
UPGRADE.md
291
UPGRADE.md
@@ -1,5 +1,272 @@
|
||||
# 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
|
||||
|
||||
Calling
|
||||
`Doctrine\ORM\Mapping\ClassMetadata::getAssociationMappedByTargetField()` with
|
||||
the owning side of an association returns `null`, which is 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.
|
||||
|
||||
## Deprecate `Doctrine\ORM\Query\Lexer::T_*` constants
|
||||
|
||||
Use `Doctrine\ORM\Query\TokenType::T_*` instead.
|
||||
|
||||
# Upgrade to 2.17
|
||||
|
||||
## Deprecate annotations classes for named queries
|
||||
|
||||
The following classes have been deprecated:
|
||||
|
||||
* `Doctrine\ORM\Mapping\NamedNativeQueries`
|
||||
* `Doctrine\ORM\Mapping\NamedNativeQuery`
|
||||
* `Doctrine\ORM\Mapping\NamedQueries`
|
||||
* `Doctrine\ORM\Mapping\NamedQuery`
|
||||
|
||||
## Deprecate `Doctrine\ORM\Query\Exec\AbstractSqlExecutor::_sqlStatements`
|
||||
|
||||
Use `Doctrine\ORM\Query\Exec\AbstractSqlExecutor::sqlStatements` instead.
|
||||
|
||||
## Undeprecate `Doctrine\ORM\Proxy\Autoloader`
|
||||
|
||||
It will be a full-fledged class, no longer extending
|
||||
`Doctrine\Common\Proxy\Autoloader` in 3.0.x.
|
||||
|
||||
## Deprecated: reliance on the non-optimal defaults that come with the `AUTO` identifier generation strategy
|
||||
|
||||
When the `AUTO` identifier generation strategy was introduced, the best
|
||||
strategy at the time was selected for each database platform.
|
||||
A lot of time has passed since then, and with ORM 3.0.0 and DBAL 4.0.0, support
|
||||
for better strategies will be added.
|
||||
|
||||
Because of that, it is now deprecated to rely on the historical defaults when
|
||||
they differ from what we will be recommended in the future.
|
||||
|
||||
Instead, you should pick a strategy for each database platform you use, and it
|
||||
will be used when using `AUTO`. As of now, only PostgreSQL is affected by this.
|
||||
|
||||
It is recommended that PostgreSQL users configure their existing and new
|
||||
applications to use `SEQUENCE` until `doctrine/dbal` 4.0.0 is released:
|
||||
|
||||
```php
|
||||
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
|
||||
use Doctrine\ORM\Configuration;
|
||||
|
||||
assert($configuration instanceof Configuration);
|
||||
$configuration->setIdentityGenerationPreferences([
|
||||
PostgreSQLPlatform::CLASS => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
|
||||
]);
|
||||
```
|
||||
|
||||
When DBAL 4 is released, `AUTO` will result in `IDENTITY`, and the above
|
||||
configuration should be removed to migrate to it.
|
||||
|
||||
## Deprecate `EntityManagerInterface::getPartialReference()`
|
||||
|
||||
This method does not have a replacement and will be removed in 3.0.
|
||||
|
||||
## Deprecate not-enabling lazy-ghosts
|
||||
|
||||
Not enabling lazy ghost objects is deprecated. In ORM 3.0, they will be always enabled.
|
||||
Ensure `Doctrine\ORM\Configuration::setLazyGhostObjectEnabled(true)` is called to enable them.
|
||||
|
||||
# Upgrade to 2.16
|
||||
|
||||
## Deprecated accepting duplicate IDs in the identity map
|
||||
|
||||
For any given entity class and ID value, there should be only one object instance
|
||||
representing the entity.
|
||||
|
||||
In https://github.com/doctrine/orm/pull/10785, a check was added that will guard this
|
||||
in the identity map. The most probable cause for violations of this rule are collisions
|
||||
of application-provided IDs.
|
||||
|
||||
In ORM 2.16.0, the check was added by throwing an exception. In ORM 2.16.1, this will be
|
||||
changed to a deprecation notice. ORM 3.0 will make it an exception again. Use
|
||||
`\Doctrine\ORM\Configuration::setRejectIdCollisionInIdentityMap()` if you want to opt-in
|
||||
to the new mode.
|
||||
|
||||
## Potential changes to the order in which `INSERT`s are executed
|
||||
|
||||
In https://github.com/doctrine/orm/pull/10547, the commit order computation was improved
|
||||
to fix a series of bugs where a correct (working) commit order was previously not found.
|
||||
Also, the new computation may get away with fewer queries being executed: By inserting
|
||||
referred-to entities first and using their ID values for foreign key fields in subsequent
|
||||
`INSERT` statements, additional `UPDATE` statements that were previously necessary can be
|
||||
avoided.
|
||||
|
||||
When using database-provided, auto-incrementing IDs, this may lead to IDs being assigned
|
||||
to entities in a different order than it was previously the case.
|
||||
|
||||
## Deprecated returning post insert IDs from `EntityPersister::executeInserts()`
|
||||
|
||||
Persisters implementing `\Doctrine\ORM\Persisters\Entity\EntityPersister` should no longer
|
||||
return an array of post insert IDs from their `::executeInserts()` method. Make the
|
||||
persister call `Doctrine\ORM\UnitOfWork::assignPostInsertId()` instead.
|
||||
|
||||
## Changing the way how reflection-based mapping drivers report fields, deprecated the "old" mode
|
||||
|
||||
In ORM 3.0, a change will be made regarding how the `AttributeDriver` reports field mappings.
|
||||
This change is necessary to be able to detect (and reject) some invalid mapping configurations.
|
||||
|
||||
To avoid surprises during 2.x upgrades, the new mode is opt-in. It can be activated on the
|
||||
`AttributeDriver` and `AnnotationDriver` by setting the `$reportFieldsWhereDeclared`
|
||||
constructor parameter to `true`. It will cause `MappingException`s to be thrown when invalid
|
||||
configurations are detected.
|
||||
|
||||
Not enabling the new mode will cause a deprecation notice to be raised. In ORM 3.0,
|
||||
only the new mode will be available.
|
||||
|
||||
# Upgrade to 2.15
|
||||
|
||||
## Deprecated configuring `JoinColumn` on the inverse side of one-to-one associations
|
||||
|
||||
For one-to-one associations, the side using the `mappedBy` attribute is the inverse side.
|
||||
The owning side is the entity with the table containing the foreign key. Using `JoinColumn`
|
||||
configuration on the _inverse_ side now triggers a deprecation notice and will be an error
|
||||
in 3.0.
|
||||
|
||||
## Deprecated overriding fields or associations not declared in mapped superclasses
|
||||
|
||||
As stated in the documentation, fields and associations may only be overridden when being inherited
|
||||
from mapped superclasses. Overriding them for parent entity classes now triggers a deprecation notice
|
||||
and will be an error in 3.0.
|
||||
|
||||
## Deprecated undeclared entity inheritance
|
||||
|
||||
As soon as an entity class inherits from another entity class, inheritance has to
|
||||
be declared by adding the appropriate configuration for the root entity.
|
||||
|
||||
## Deprecated stubs for "concrete table inheritance"
|
||||
|
||||
This third way of mapping class inheritance was never implemented. Code stubs are
|
||||
now deprecated and will be removed in 3.0.
|
||||
|
||||
* `\Doctrine\ORM\Mapping\ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS` constant
|
||||
* `\Doctrine\ORM\Mapping\ClassMetadataInfo::isInheritanceTypeTablePerClass()` method
|
||||
* Using `TABLE_PER_CLASS` as the value for the `InheritanceType` attribute or annotation
|
||||
or in XML configuration files.
|
||||
|
||||
# Upgrade to 2.14
|
||||
|
||||
## Deprecated `Doctrine\ORM\Persisters\Exception\UnrecognizedField::byName($field)` method.
|
||||
|
||||
Use `Doctrine\ORM\Persisters\Exception\UnrecognizedField::byFullyQualifiedName($className, $field)` instead.
|
||||
|
||||
## Deprecated constants of `Doctrine\ORM\Internal\CommitOrderCalculator`
|
||||
|
||||
The following public constants have been deprecated:
|
||||
|
||||
* `CommitOrderCalculator::NOT_VISITED`
|
||||
* `CommitOrderCalculator::IN_PROGRESS`
|
||||
* `CommitOrderCalculator::VISITED`
|
||||
|
||||
These constants were used for internal purposes. Relying on them is discouraged.
|
||||
|
||||
## Deprecated `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 deprecated in favor of
|
||||
`SqlWalker::walkInListExpression()` and `SqlWalker::walkInSubselectExpression()`.
|
||||
|
||||
## Deprecated constructing a `CacheKey` without `$hash`
|
||||
|
||||
The `Doctrine\ORM\Cache\CacheKey` class has an explicit constructor now with
|
||||
an optional parameter `$hash`. That parameter will become mandatory in 3.0.
|
||||
|
||||
## Deprecated `AttributeDriver::$entityAnnotationClasses`
|
||||
|
||||
If you need to change the behavior of `AttributeDriver::isTransient()`,
|
||||
override that method instead.
|
||||
|
||||
## Deprecated incomplete schema updates
|
||||
|
||||
Using `orm:schema-tool:update` without passing the `--complete` flag is
|
||||
deprecated. Use schema asset filtering if you need to preserve assets not
|
||||
managed by DBAL.
|
||||
|
||||
Likewise, calling `SchemaTool::updateSchema()` or
|
||||
`SchemaTool::getUpdateSchemaSql()` with a second argument is deprecated.
|
||||
|
||||
## Deprecated annotation mapping driver.
|
||||
|
||||
Please switch to one of the other mapping drivers. Native attributes which PHP
|
||||
supports since version 8.0 are probably your best option.
|
||||
|
||||
As a consequence, the following methods are deprecated:
|
||||
- `ORMSetup::createAnnotationMetadataConfiguration`
|
||||
- `ORMSetup::createDefaultAnnotationDriver`
|
||||
|
||||
The marker interface `Doctrine\ORM\Mapping\Annotation` is deprecated as well.
|
||||
All annotation/attribute classes implement
|
||||
`Doctrine\ORM\Mapping\MappingAttribute` now.
|
||||
|
||||
## Deprecated `Doctrine\ORM\Proxy\Proxy` interface.
|
||||
|
||||
Use `Doctrine\Persistence\Proxy` instead to check whether proxies are initialized.
|
||||
|
||||
## Deprecated `Doctrine\ORM\Event\LifecycleEventArgs` class.
|
||||
|
||||
It will be removed in 3.0. 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`
|
||||
|
||||
# Upgrade to 2.13
|
||||
|
||||
## Deprecated `EntityManager::create()`
|
||||
|
||||
The constructor of `EntityManager` is now public and should 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.
|
||||
|
||||
## Deprecated `QueryBuilder` methods and constants.
|
||||
|
||||
1. The `QueryBuilder::getState()` method has been deprecated as the builder state is an internal concern.
|
||||
@@ -394,7 +661,7 @@ function foo(EntityManagerInterface $entityManager, callable $func) {
|
||||
if (method_exists($entityManager, 'wrapInTransaction')) {
|
||||
return $entityManager->wrapInTransaction($func);
|
||||
}
|
||||
|
||||
|
||||
return $entityManager->transactional($func);
|
||||
}
|
||||
```
|
||||
@@ -460,7 +727,7 @@ implementation. To work around this:
|
||||
* As a quick workaround, you can lock the doctrine/cache dependency to work around this: `composer require doctrine/cache ^1.11`.
|
||||
Note that this is only recommended as a bandaid fix, as future versions of ORM will no longer work with doctrine/cache
|
||||
1.11.
|
||||
|
||||
|
||||
## Deprecated: doctrine/cache for metadata caching
|
||||
|
||||
The `Doctrine\ORM\Configuration#setMetadataCacheImpl()` method is deprecated and should no longer be used. Please use
|
||||
@@ -485,12 +752,12 @@ Note that `toIterable()` yields results of the query, unlike `iterate()` which y
|
||||
|
||||
# Upgrade to 2.7
|
||||
|
||||
## Added `Doctrine\ORM\AbstractQuery#enableResultCache()` and `Doctrine\ORM\AbstractQuery#disableResultCache()` methods
|
||||
## Added `Doctrine\ORM\AbstractQuery#enableResultCache()` and `Doctrine\ORM\AbstractQuery#disableResultCache()` methods
|
||||
|
||||
Method `Doctrine\ORM\AbstractQuery#useResultCache()` which could be used for both enabling and disabling the cache
|
||||
(depending on passed flag) was split into two.
|
||||
(depending on passed flag) was split into two.
|
||||
|
||||
## Minor BC BREAK: paginator output walkers aren't be called anymore on sub-queries for queries without max results
|
||||
## Minor BC BREAK: paginator output walkers aren't be called anymore on sub-queries for queries without max results
|
||||
|
||||
To optimize DB interaction, `Doctrine\ORM\Tools\Pagination\Paginator` no longer fetches identifiers to be able to
|
||||
perform the pagination with join collections when max results isn't set in the query.
|
||||
@@ -509,7 +776,7 @@ In the last patch of the `v2.6.x` series, we fixed a bug that was not converting
|
||||
In order to not break BC we've introduced a way to enable the fixed behavior using a boolean constructor argument. This
|
||||
argument will be removed in 3.0 and the default behavior will be the fixed one.
|
||||
|
||||
## Deprecated: `Doctrine\ORM\AbstractQuery#useResultCache()`
|
||||
## Deprecated: `Doctrine\ORM\AbstractQuery#useResultCache()`
|
||||
|
||||
Method `Doctrine\ORM\AbstractQuery#useResultCache()` is deprecated because it is split into `enableResultCache()`
|
||||
and `disableResultCache()`. It will be removed in 3.0.
|
||||
@@ -539,7 +806,7 @@ These related classes have been deprecated:
|
||||
|
||||
* `Doctrine\ORM\Proxy\ProxyFactory`
|
||||
* `Doctrine\ORM\Proxy\Autoloader` - we suggest using the composer autoloader instead
|
||||
|
||||
|
||||
These methods have been deprecated:
|
||||
|
||||
* `Doctrine\ORM\Configuration#getAutoGenerateProxyClasses()`
|
||||
@@ -588,7 +855,7 @@ If your code relies on single entity flushing optimisations via
|
||||
|
||||
Said API was affected by multiple data integrity bugs due to the fact
|
||||
that change tracking was being restricted upon a subset of the managed
|
||||
entities. The ORM cannot support committing subsets of the managed
|
||||
entities. The ORM cannot support committing subsets of the managed
|
||||
entities while also guaranteeing data integrity, therefore this
|
||||
utility was removed.
|
||||
|
||||
@@ -689,8 +956,8 @@ either:
|
||||
- map those classes as `MappedSuperclass`
|
||||
|
||||
## Minor BC BREAK: ``EntityManagerInterface`` instead of ``EntityManager`` in type-hints
|
||||
|
||||
As of 2.5, classes requiring the ``EntityManager`` in any method signature will now require
|
||||
|
||||
As of 2.5, classes requiring the ``EntityManager`` in any method signature will now require
|
||||
an ``EntityManagerInterface`` instead.
|
||||
If you are extending any of the following classes, then you need to check following
|
||||
signatures:
|
||||
@@ -783,7 +1050,7 @@ the `Doctrine\ORM\Repository\DefaultRepositoryFactory`.
|
||||
When executing DQL queries with new object expressions, instead of returning DTOs numerically indexes, it will now respect user provided aliases. Consider the following query:
|
||||
|
||||
SELECT new UserDTO(u.id,u.name) as user,new AddressDTO(a.street,a.postalCode) as address, a.id as addressId FROM User u INNER JOIN u.addresses a WITH a.isPrimary = true
|
||||
|
||||
|
||||
Previously, your result would be similar to this:
|
||||
|
||||
array(
|
||||
@@ -1021,7 +1288,7 @@ The EntityRepository now has an interface Doctrine\Persistence\ObjectRepository.
|
||||
The annotation reader was heavily refactored between 2.0 and 2.1-RC1. In theory the operation of the new reader should be backwards compatible, but it has to be setup differently to work that way:
|
||||
|
||||
// new call to the AnnotationRegistry
|
||||
\Doctrine\Common\Annotations\AnnotationRegistry::registerFile('/doctrine-src/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php');
|
||||
\Doctrine\Common\Annotations\AnnotationRegistry::registerFile('/doctrine-src/src/Mapping/Driver/DoctrineAnnotations.php');
|
||||
|
||||
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
|
||||
$reader->setDefaultAnnotationNamespace('Doctrine\ORM\Mapping\\');
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">../../../lib/Doctrine</directory>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">../../../lib/Doctrine</directory>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">../../../lib/Doctrine</directory>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">../../../lib/Doctrine</directory>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
|
||||
40
ci/github/phpunit/pgsql.xml
Normal file
40
ci/github/phpunit/pgsql.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
failOnRisky="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
<var name="db_driver" value="pgsql"/>
|
||||
<var name="db_host" value="localhost" />
|
||||
<var name="db_user" value="postgres" />
|
||||
<var name="db_password" value="postgres" />
|
||||
<var name="db_dbname" value="doctrine_tests" />
|
||||
|
||||
<!-- necessary change for some CLI/console output test assertions -->
|
||||
<env name="COLUMNS" value="120"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Doctrine DBAL Test Suite">
|
||||
<directory>../../../tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
<group>performance</group>
|
||||
<group>locking_functional</group>
|
||||
</exclude>
|
||||
</groups>
|
||||
</phpunit>
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">../../../lib/Doctrine</directory>
|
||||
<directory suffix=".php">../../../src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
@@ -24,34 +25,36 @@
|
||||
"composer-runtime-api": "^2",
|
||||
"ext-ctype": "*",
|
||||
"doctrine/cache": "^1.12.1 || ^2.1.1",
|
||||
"doctrine/collections": "^1.5",
|
||||
"doctrine/collections": "^1.5 || ^2.1",
|
||||
"doctrine/common": "^3.0.3",
|
||||
"doctrine/dbal": "^2.13.1 || ^3.2",
|
||||
"doctrine/deprecations": "^0.5.3 || ^1",
|
||||
"doctrine/event-manager": "^1.1",
|
||||
"doctrine/event-manager": "^1.2 || ^2",
|
||||
"doctrine/inflector": "^1.4 || ^2.0",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
"doctrine/lexer": "^1.2.3",
|
||||
"doctrine/instantiator": "^1.3 || ^2",
|
||||
"doctrine/lexer": "^2 || ^3",
|
||||
"doctrine/persistence": "^2.4 || ^3",
|
||||
"psr/cache": "^1 || ^2 || ^3",
|
||||
"symfony/console": "^3.0 || ^4.0 || ^5.0 || ^6.0",
|
||||
"symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0",
|
||||
"symfony/polyfill-php72": "^1.23",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "^1.13",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^11.0",
|
||||
"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.9.4",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"phpstan/extension-installer": "~1.1.0 || ^1.4",
|
||||
"phpstan/phpstan": "~1.4.10 || 2.0.3",
|
||||
"phpstan/phpstan-deprecation-rules": "^1 || ^2",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.7.1",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
|
||||
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
|
||||
"vimeo/psalm": "4.30.0 || 5.3.0"
|
||||
"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"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/annotations": "<1.13 || >= 2.0"
|
||||
"doctrine/annotations": "<1.13 || >= 3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Provides support for XSD validation for XML mapping files",
|
||||
@@ -59,13 +62,13 @@
|
||||
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Doctrine\\ORM\\": "lib/Doctrine/ORM" }
|
||||
"psr-4": { "Doctrine\\ORM\\": "src" }
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Tests\\": "tests/Doctrine/Tests",
|
||||
"Doctrine\\StaticAnalysis\\": "tests/Doctrine/StaticAnalysis",
|
||||
"Doctrine\\Performance\\": "tests/Doctrine/Performance"
|
||||
"Doctrine\\Tests\\": "tests/Tests",
|
||||
"Doctrine\\StaticAnalysis\\": "tests/StaticAnalysis",
|
||||
"Doctrine\\Performance\\": "tests/Performance"
|
||||
}
|
||||
},
|
||||
"bin": ["bin/doctrine"],
|
||||
|
||||
4
docs/.gitignore
vendored
4
docs/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
en/_exts/configurationblock.pyc
|
||||
build
|
||||
en/_build
|
||||
.idea
|
||||
3
docs/.gitmodules
vendored
3
docs/.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "en/_theme"]
|
||||
path = en/_theme
|
||||
url = https://github.com/doctrine/doctrine-sphinx-theme.git
|
||||
@@ -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
@@ -1,74 +0,0 @@
|
||||
Accessing private/protected properties/methods of the same class from different instance
|
||||
========================================================================================
|
||||
|
||||
.. sectionauthor:: Michael Olsavsky (olsavmic)
|
||||
|
||||
As explained in the :doc:`restrictions for entity classes in the manual <../reference/architecture>`,
|
||||
it is dangerous to access private/protected properties of different entity instance of the same class because of lazy loading.
|
||||
|
||||
The proxy instance that's injected instead of the real entity may not be initialized yet
|
||||
and therefore not contain expected data which may result in unexpected behavior.
|
||||
That's a limitation of current proxy implementation - only public methods automatically initialize proxies.
|
||||
|
||||
It is usually preferable to use a public interface to manipulate the object from outside the `$this`
|
||||
context but it may not be convenient in some cases. The following example shows how to do it safely.
|
||||
|
||||
Safely accessing private properties from different instance of the same class
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
To safely access private property of different instance of the same class, make sure to initialise
|
||||
the proxy before use manually as follows:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\Common\Proxy\Proxy;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class Entity
|
||||
{
|
||||
// ...
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Entity")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
private self $parent;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", nullable=false)
|
||||
*/
|
||||
private string $name;
|
||||
|
||||
// ...
|
||||
|
||||
public function doSomethingWithParent()
|
||||
{
|
||||
// Always initializing the proxy before use
|
||||
if ($this->parent instanceof Proxy) {
|
||||
$this->parent->__load();
|
||||
}
|
||||
|
||||
// Accessing the `$this->parent->name` property without loading the proxy first
|
||||
// may throw error in case the Proxy has not been initialized yet.
|
||||
$this->parent->name;
|
||||
}
|
||||
|
||||
public function doSomethingWithAnotherInstance(self $instance)
|
||||
{
|
||||
// Always initializing the proxy before use
|
||||
if ($instance instanceof Proxy) {
|
||||
$instance->__load();
|
||||
}
|
||||
|
||||
// Accessing the `$instance->name` property without loading the proxy first
|
||||
// may throw error in case the Proxy has not been initialized yet.
|
||||
$instance->name;
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
@@ -196,7 +196,7 @@ Example usage
|
||||
<?php
|
||||
|
||||
// Bootstrapping stuff...
|
||||
// $em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);
|
||||
// $em = new \Doctrine\ORM\EntityManager($connection, $config);
|
||||
|
||||
// Setup custom mapping type
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
@@ -36,71 +36,50 @@ Our entities look like:
|
||||
namespace Bank\Entities;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
#[ORM\Entity]
|
||||
class Account
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", unique=true)
|
||||
*/
|
||||
private string $no;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="Entry", mappedBy="account", cascade={"persist"})
|
||||
*/
|
||||
private array $entries;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private int $maxCredit = 0;
|
||||
|
||||
public function __construct(string $no, int $maxCredit = 0)
|
||||
{
|
||||
$this->no = $no;
|
||||
$this->maxCredit = $maxCredit;
|
||||
$this->entries = new \Doctrine\Common\Collections\ArrayCollection();
|
||||
|
||||
#[ORM\OneToMany(targetEntity: Entry::class, mappedBy: 'account', cascade: ['persist'])]
|
||||
private Collection $entries;
|
||||
|
||||
|
||||
public function __construct(
|
||||
#[ORM\Column(type: 'string', unique: true)]
|
||||
private string $no,
|
||||
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int $maxCredit = 0,
|
||||
) {
|
||||
$this->entries = new ArrayCollection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
|
||||
#[ORM\Entity]
|
||||
class Entry
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private ?int $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Account", inversedBy="entries")
|
||||
*/
|
||||
private Account $account;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private int $amount;
|
||||
|
||||
public function __construct(Account $account, int $amount)
|
||||
{
|
||||
$this->account = $account;
|
||||
$this->amount = $amount;
|
||||
|
||||
public function __construct(
|
||||
#[ORM\ManyToOne(targetEntity: Account::class, inversedBy: 'entries')]
|
||||
private Account $account,
|
||||
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int $amount,
|
||||
) {
|
||||
// more stuff here, from/to whom, stated reason, execution date and such
|
||||
}
|
||||
|
||||
|
||||
public function getAmount(): Amount
|
||||
{
|
||||
return $this->amount;
|
||||
@@ -193,9 +172,8 @@ relation with this method:
|
||||
public function addEntry(int $amount): void
|
||||
{
|
||||
$this->assertAcceptEntryAllowed($amount);
|
||||
|
||||
$e = new Entry($this, $amount);
|
||||
$this->entries[] = $e;
|
||||
|
||||
$this->entries[] = new Entry($this, $amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,20 +189,20 @@ Now look at the following test-code for our entities:
|
||||
{
|
||||
public function testAddEntry()
|
||||
{
|
||||
$account = new Account("123456", $maxCredit = 200);
|
||||
$account = new Account("123456", maxCredit: 200);
|
||||
$this->assertEquals(0, $account->getBalance());
|
||||
|
||||
|
||||
$account->addEntry(500);
|
||||
$this->assertEquals(500, $account->getBalance());
|
||||
|
||||
|
||||
$account->addEntry(-700);
|
||||
$this->assertEquals(-200, $account->getBalance());
|
||||
}
|
||||
|
||||
|
||||
public function testExceedMaxLimit()
|
||||
{
|
||||
$account = new Account("123456", $maxCredit = 200);
|
||||
|
||||
$account = new Account("123456", maxCredit: 200);
|
||||
|
||||
$this->expectException(Exception::class);
|
||||
$account->addEntry(-1000);
|
||||
}
|
||||
@@ -285,22 +263,19 @@ entries collection) we want to add an aggregate field called
|
||||
<?php
|
||||
class Account
|
||||
{
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
#[ORM\Column(type: 'integer')]
|
||||
private int $balance = 0;
|
||||
|
||||
|
||||
public function getBalance(): int
|
||||
{
|
||||
return $this->balance;
|
||||
}
|
||||
|
||||
|
||||
public function addEntry(int $amount): void
|
||||
{
|
||||
$this->assertAcceptEntryAllowed($amount);
|
||||
|
||||
$e = new Entry($this, $amount);
|
||||
$this->entries[] = $e;
|
||||
|
||||
$this->entries[] = new Entry($this, $amount);
|
||||
$this->balance += $amount;
|
||||
}
|
||||
}
|
||||
@@ -331,13 +306,13 @@ potentially lead to inconsistent state. See this example:
|
||||
// The Account $accId has a balance of 0 and a max credit limit of 200:
|
||||
// request 1 account
|
||||
$account1 = $em->find(Account::class, $accId);
|
||||
|
||||
|
||||
// request 2 account
|
||||
$account2 = $em->find(Account::class, $accId);
|
||||
|
||||
|
||||
$account1->addEntry(-200);
|
||||
$account2->addEntry(-200);
|
||||
|
||||
|
||||
// now request 1 and 2 both flush the changes.
|
||||
|
||||
The aggregate field ``Account::$balance`` is now -200, however the
|
||||
@@ -357,10 +332,8 @@ Optimistic locking is as easy as adding a version column:
|
||||
|
||||
class Account
|
||||
{
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Version
|
||||
*/
|
||||
#[ORM\Column(type: 'integer')]
|
||||
#[ORM\Version]
|
||||
private int $version;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ configuration:
|
||||
$config->addCustomNumericFunction($name, $class);
|
||||
$config->addCustomDatetimeFunction($name, $class);
|
||||
|
||||
$em = EntityManager::create($dbParams, $config);
|
||||
$em = new EntityManager($connection, $config);
|
||||
|
||||
The ``$name`` is the name the function will be referred to in the
|
||||
DQL query. ``$class`` is a string of a class-name which has to
|
||||
@@ -99,12 +99,12 @@ discuss it step by step:
|
||||
|
||||
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER); // (2)
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS); // (3)
|
||||
$parser->match(TokenType::T_IDENTIFIER); // (2)
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS); // (3)
|
||||
$this->firstDateExpression = $parser->ArithmeticPrimary(); // (4)
|
||||
$parser->match(Lexer::T_COMMA); // (5)
|
||||
$parser->match(TokenType::T_COMMA); // (5)
|
||||
$this->secondDateExpression = $parser->ArithmeticPrimary(); // (6)
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS); // (3)
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS); // (3)
|
||||
}
|
||||
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
@@ -183,23 +183,23 @@ I'll skip the blah and show the code for this function:
|
||||
|
||||
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstDateExpression = $parser->ArithmeticPrimary();
|
||||
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_COMMA);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
|
||||
$this->intervalExpression = $parser->ArithmeticPrimary();
|
||||
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
|
||||
/** @var Lexer $lexer */
|
||||
$lexer = $parser->getLexer();
|
||||
$this->unit = $lexer->token['value'];
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
@@ -247,5 +247,3 @@ vendor sql functions and extend the DQL languages scope.
|
||||
Code for this Extension to DQL and other Doctrine Extensions can be
|
||||
found
|
||||
`in the GitHub DoctrineExtensions repository <https://github.com/beberlei/DoctrineExtensions>`_.
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Implementing ArrayAccess for Domain Objects
|
||||
===========================================
|
||||
|
||||
.. sectionauthor:: Roman Borschel (roman@code-factory.org)
|
||||
.. sectionauthor:: Roman Borschel <roman@code-factory.org>
|
||||
|
||||
This recipe will show you how to implement ArrayAccess for your
|
||||
domain objects in order to allow more uniform access, for example
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Implementing the Notify ChangeTracking Policy
|
||||
=============================================
|
||||
|
||||
.. sectionauthor:: Roman Borschel (roman@code-factory.org)
|
||||
.. 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
|
||||
@@ -13,7 +13,7 @@ for all our domain objects.
|
||||
.. note::
|
||||
|
||||
The notify change tracking policy is deprecated and will be removed in ORM 3.0.
|
||||
(`Details <https://github.com/doctrine/orm/issues/8383>`_)
|
||||
(\ `Details <https://github.com/doctrine/orm/issues/8383>`_)
|
||||
|
||||
Implementing NotifyPropertyChanged
|
||||
----------------------------------
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
Implementing Wakeup or Clone
|
||||
============================
|
||||
|
||||
.. sectionauthor:: Roman Borschel (roman@code-factory.org)
|
||||
|
||||
As explained in the :ref:`restrictions for entity classes in the manual
|
||||
<terminology_entities>`,
|
||||
it is usually not allowed for an entity to implement ``__wakeup``
|
||||
or ``__clone``, because Doctrine makes special use of them.
|
||||
However, it is quite easy to make use of these methods in a safe
|
||||
way by guarding the custom wakeup or clone code with an entity
|
||||
identity check, as demonstrated in the following sections.
|
||||
|
||||
Safely implementing __wakeup
|
||||
----------------------------
|
||||
|
||||
To safely implement ``__wakeup``, simply enclose your
|
||||
implementation code in an identity check as follows:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class MyEntity
|
||||
{
|
||||
private $id; // This is the identifier of the entity.
|
||||
// ...
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
// If the entity has an identity, proceed as normal.
|
||||
if ($this->id) {
|
||||
// ... Your code here as normal ...
|
||||
}
|
||||
// otherwise do nothing, do NOT throw an exception!
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
Safely implementing __clone
|
||||
---------------------------
|
||||
|
||||
Safely implementing ``__clone`` is pretty much the same:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class MyEntity
|
||||
{
|
||||
private $id; // This is the identifier of the entity.
|
||||
// ...
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
// If the entity has an identity, proceed as normal.
|
||||
if ($this->id) {
|
||||
// ... Your code here as normal ...
|
||||
}
|
||||
// otherwise do nothing, do NOT throw an exception!
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
Summary
|
||||
-------
|
||||
|
||||
As you have seen, it is quite easy to safely make use of
|
||||
``__wakeup`` and ``__clone`` in your entities without adding any
|
||||
really Doctrine-specific or Doctrine-dependant code.
|
||||
|
||||
These implementations are possible and safe because when Doctrine
|
||||
invokes these methods, the entities never have an identity (yet).
|
||||
Furthermore, it is possibly a good idea to check for the identity
|
||||
in your code anyway, since it's rarely the case that you want to
|
||||
unserialize or clone an entity with no identity.
|
||||
|
||||
|
||||
@@ -47,10 +47,8 @@ A Customer entity
|
||||
use Acme\CustomerModule\Entity\Customer as BaseCustomer;
|
||||
use Acme\InvoiceModule\Model\InvoiceSubjectInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="customer")
|
||||
*/
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'customer')]
|
||||
class Customer extends BaseCustomer implements InvoiceSubjectInterface
|
||||
{
|
||||
// In our example, any methods defined in the InvoiceSubjectInterface
|
||||
@@ -69,19 +67,12 @@ An Invoice entity
|
||||
use Doctrine\ORM\Mapping AS ORM;
|
||||
use Acme\InvoiceModule\Model\InvoiceSubjectInterface;
|
||||
|
||||
/**
|
||||
* Represents an Invoice.
|
||||
*
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="invoice")
|
||||
*/
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'invoice')]
|
||||
class Invoice
|
||||
{
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Acme\InvoiceModule\Model\InvoiceSubjectInterface")
|
||||
* @var InvoiceSubjectInterface
|
||||
*/
|
||||
protected $subject;
|
||||
#[ORM\ManyToOne(targetEntity: InvoiceSubjectInterface::class)]
|
||||
protected InvoiceSubjectInterface $subject;
|
||||
}
|
||||
|
||||
An InvoiceSubjectInterface
|
||||
@@ -127,7 +118,8 @@ the targetEntity resolution will occur reliably:
|
||||
// Add the ResolveTargetEntityListener
|
||||
$evm->addEventListener(Doctrine\ORM\Events::loadClassMetadata, $rtel);
|
||||
|
||||
$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config, $evm);
|
||||
$connection = \Doctrine\DBAL\DriverManager::getConnection($connectionOptions, $config, $evm);
|
||||
$em = new \Doctrine\ORM\EntityManager($connection, $config, $evm);
|
||||
|
||||
Final Thoughts
|
||||
--------------
|
||||
@@ -136,5 +128,3 @@ With the ``ResolveTargetEntityListener``, we are able to decouple our
|
||||
bundles, keeping them usable by themselves, but still being able to
|
||||
define relationships between different objects. By using this method,
|
||||
I've found my bundles end up being easier to maintain independently.
|
||||
|
||||
|
||||
|
||||
@@ -81,6 +81,4 @@ before the prefix has been set.
|
||||
$tablePrefix = new \DoctrineExtensions\TablePrefix('prefix_');
|
||||
$evm->addEventListener(\Doctrine\ORM\Events::loadClassMetadata, $tablePrefix);
|
||||
|
||||
$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config, $evm);
|
||||
|
||||
|
||||
$em = new \Doctrine\ORM\EntityManager($connection, $config, $evm);
|
||||
|
||||
@@ -11,7 +11,7 @@ What we offer are hooks to execute any kind of validation.
|
||||
.. note::
|
||||
|
||||
You don't need to validate your entities in the lifecycle
|
||||
events. Its only one of many options. Of course you can also
|
||||
events. It is only one of many options. Of course you can also
|
||||
perform validations in value setters or any other method of your
|
||||
entities that are used in your code.
|
||||
|
||||
@@ -58,6 +58,10 @@ First Attributes:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
|
||||
use Doctrine\ORM\Mapping\PrePersist;
|
||||
use Doctrine\ORM\Mapping\PreUpdate;
|
||||
|
||||
#[Entity]
|
||||
#[HasLifecycleCallbacks]
|
||||
|
||||
@@ -21,7 +21,7 @@ these comparisons are always made **BY REFERENCE**. That means the following cha
|
||||
#[Entity]
|
||||
class Article
|
||||
{
|
||||
#[Column(type='datetime')]
|
||||
#[Column(type: 'datetime')]
|
||||
private DateTime $updated;
|
||||
|
||||
public function setUpdated(): void
|
||||
|
||||
@@ -18,8 +18,8 @@ Doctrine ORM don't panic. You can get help from different sources:
|
||||
- Report a bug on `GitHub <https://github.com/doctrine/orm/issues>`_.
|
||||
- On `StackOverflow <https://stackoverflow.com/questions/tagged/doctrine-orm>`_
|
||||
|
||||
If you need more structure over the different topics you can browse the :doc:`table
|
||||
of contents <toc>`.
|
||||
If you need more structure over the different topics you can browse the table
|
||||
of contents.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
@@ -34,32 +34,32 @@ Mapping Objects onto a Database
|
||||
-------------------------------
|
||||
|
||||
* **Mapping**:
|
||||
:doc:`Objects <reference/basic-mapping>` |
|
||||
:doc:`Associations <reference/association-mapping>` |
|
||||
:doc:`Objects <reference/basic-mapping>` \|
|
||||
:doc:`Associations <reference/association-mapping>` \|
|
||||
:doc:`Inheritance <reference/inheritance-mapping>`
|
||||
|
||||
* **Drivers**:
|
||||
:doc:`Docblock Annotations <reference/annotations-reference>` |
|
||||
:doc:`Attributes <reference/attributes-reference>` |
|
||||
:doc:`XML <reference/xml-mapping>` |
|
||||
:doc:`YAML <reference/yaml-mapping>` |
|
||||
:doc:`Docblock Annotations <reference/annotations-reference>` \|
|
||||
:doc:`Attributes <reference/attributes-reference>` \|
|
||||
:doc:`XML <reference/xml-mapping>` \|
|
||||
:doc:`YAML <reference/yaml-mapping>` \|
|
||||
:doc:`PHP <reference/php-mapping>`
|
||||
|
||||
Working with Objects
|
||||
--------------------
|
||||
|
||||
* **Basic Reference**:
|
||||
:doc:`Entities <reference/working-with-objects>` |
|
||||
:doc:`Associations <reference/working-with-associations>` |
|
||||
:doc:`Entities <reference/working-with-objects>` \|
|
||||
:doc:`Associations <reference/working-with-associations>` \|
|
||||
:doc:`Events <reference/events>`
|
||||
|
||||
* **Query Reference**:
|
||||
:doc:`DQL <reference/dql-doctrine-query-language>` |
|
||||
:doc:`QueryBuilder <reference/query-builder>` |
|
||||
:doc:`DQL <reference/dql-doctrine-query-language>` \|
|
||||
:doc:`QueryBuilder <reference/query-builder>` \|
|
||||
:doc:`Native SQL <reference/native-sql>`
|
||||
|
||||
* **Internals**:
|
||||
:doc:`Internals explained <reference/unitofwork>` |
|
||||
:doc:`Internals explained <reference/unitofwork>` \|
|
||||
:doc:`Associations <reference/unitofwork-associations>`
|
||||
|
||||
Advanced Topics
|
||||
@@ -72,6 +72,7 @@ Advanced Topics
|
||||
* :doc:`Transactions and Concurrency <reference/transactions-and-concurrency>`
|
||||
* :doc:`Filters <reference/filters>`
|
||||
* :doc:`NamingStrategy <reference/namingstrategy>`
|
||||
* :doc:`TypedFieldMapper <reference/typedfieldmapper>`
|
||||
* :doc:`Improving Performance <reference/improving-performance>`
|
||||
* :doc:`Caching <reference/caching>`
|
||||
* :doc:`Partial Objects <reference/partial-objects>`
|
||||
@@ -95,27 +96,26 @@ Tutorials
|
||||
Changelogs
|
||||
----------
|
||||
|
||||
* `Upgrade <https://github.com/doctrine/doctrine2/blob/master/UPGRADE.md>`_
|
||||
* `Upgrade <https://github.com/doctrine/orm/blob/HEAD/UPGRADE.md>`_
|
||||
|
||||
Cookbook
|
||||
--------
|
||||
|
||||
* **Patterns**:
|
||||
:doc:`Aggregate Fields <cookbook/aggregate-fields>` |
|
||||
:doc:`Decorator Pattern <cookbook/decorator-pattern>` |
|
||||
:doc:`Aggregate Fields <cookbook/aggregate-fields>` \|
|
||||
:doc:`Decorator Pattern <cookbook/decorator-pattern>` \|
|
||||
:doc:`Strategy Pattern <cookbook/strategy-cookbook-introduction>`
|
||||
|
||||
* **DQL Extension Points**:
|
||||
:doc:`DQL Custom Walkers <cookbook/dql-custom-walkers>` |
|
||||
:doc:`DQL Custom Walkers <cookbook/dql-custom-walkers>` \|
|
||||
:doc:`DQL User-Defined-Functions <cookbook/dql-user-defined-functions>`
|
||||
|
||||
* **Implementation**:
|
||||
:doc:`Array Access <cookbook/implementing-arrayaccess-for-domain-objects>` |
|
||||
:doc:`Notify ChangeTracking Example <cookbook/implementing-the-notify-changetracking-policy>` |
|
||||
:doc:`Using Wakeup Or Clone <cookbook/implementing-wakeup-or-clone>` |
|
||||
:doc:`Working with DateTime <cookbook/working-with-datetime>` |
|
||||
:doc:`Validation <cookbook/validation-of-entities>` |
|
||||
:doc:`Entities in the Session <cookbook/entities-in-session>` |
|
||||
:doc:`Array Access <cookbook/implementing-arrayaccess-for-domain-objects>` \|
|
||||
:doc:`Notify ChangeTracking Example <cookbook/implementing-the-notify-changetracking-policy>` \|
|
||||
:doc:`Working with DateTime <cookbook/working-with-datetime>` \|
|
||||
:doc:`Validation <cookbook/validation-of-entities>` \|
|
||||
:doc:`Entities in the Session <cookbook/entities-in-session>` \|
|
||||
:doc:`Keeping your Modules independent <cookbook/resolve-target-entity-listener>`
|
||||
|
||||
* **Hidden Gems**
|
||||
@@ -124,5 +124,3 @@ Cookbook
|
||||
* **Custom Datatypes**
|
||||
:doc:`MySQL Enums <cookbook/mysql-enums>`
|
||||
:doc:`Advanced Field Value Conversion <cookbook/advanced-field-value-conversion-using-custom-mapping-types>`
|
||||
|
||||
.. include:: toc.rst
|
||||
|
||||
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
|
||||
@@ -29,7 +29,7 @@ steps of configuration.
|
||||
|
||||
$config = new Configuration;
|
||||
$config->setMetadataCache($metadataCache);
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']);
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
$config->setQueryCache($queryCache);
|
||||
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
|
||||
@@ -41,12 +41,12 @@ steps of configuration.
|
||||
$config->setAutoGenerateProxyClasses(false);
|
||||
}
|
||||
|
||||
$connectionOptions = array(
|
||||
$connection = DriverManager::getConnection([
|
||||
'driver' => 'pdo_sqlite',
|
||||
'path' => 'database.sqlite'
|
||||
);
|
||||
'path' => 'database.sqlite',
|
||||
], $config);
|
||||
|
||||
$em = EntityManager::create($connectionOptions, $config);
|
||||
$em = new EntityManager($connection, $config);
|
||||
|
||||
Doctrine and Caching
|
||||
--------------------
|
||||
@@ -114,11 +114,13 @@ classes.
|
||||
There are currently 5 available implementations:
|
||||
|
||||
|
||||
- ``Doctrine\ORM\Mapping\Driver\AnnotationDriver``
|
||||
- ``Doctrine\ORM\Mapping\Driver\AttributeDriver``
|
||||
- ``Doctrine\ORM\Mapping\Driver\XmlDriver``
|
||||
- ``Doctrine\ORM\Mapping\Driver\YamlDriver``
|
||||
- ``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
|
||||
@@ -132,7 +134,7 @@ The attribute driver can be injected in the ``Doctrine\ORM\Configuration``:
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
|
||||
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']);
|
||||
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
|
||||
The path information to the entities is required for the attribute
|
||||
@@ -214,7 +216,7 @@ option that controls this behavior is:
|
||||
|
||||
Possible values for ``$mode`` are:
|
||||
|
||||
- ``Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_NEVER``
|
||||
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_NEVER``
|
||||
|
||||
Never autogenerate a proxy. You will need to generate the proxies
|
||||
manually, for this use the Doctrine Console like so:
|
||||
@@ -230,17 +232,17 @@ methods were added to the entity class that are not yet in the proxy class.
|
||||
In such a case, simply use the Doctrine Console to (re)generate the
|
||||
proxy classes.
|
||||
|
||||
- ``Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_ALWAYS``
|
||||
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_ALWAYS``
|
||||
|
||||
Always generates a new proxy in every request and writes it to disk.
|
||||
|
||||
- ``Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS``
|
||||
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS``
|
||||
|
||||
Generate the proxy class when the proxy file does not exist.
|
||||
This strategy causes a file exists call whenever any proxy is
|
||||
used the first time in a request.
|
||||
|
||||
- ``Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_EVAL``
|
||||
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_EVAL``
|
||||
|
||||
Generate the proxy classes and evaluate them on the fly via eval(),
|
||||
avoiding writing the proxies to disk.
|
||||
@@ -274,15 +276,13 @@ proxy sets an exclusive file lock which can cause serious
|
||||
performance bottlenecks in systems with regular concurrent
|
||||
requests.
|
||||
|
||||
Connection Options
|
||||
------------------
|
||||
Connection
|
||||
----------
|
||||
|
||||
The ``$connectionOptions`` passed as the first argument to
|
||||
``EntityManager::create()`` has to be either an array or an
|
||||
instance of ``Doctrine\DBAL\Connection``. If an array is passed it
|
||||
is directly passed along to the DBAL Factory
|
||||
``Doctrine\DBAL\DriverManager::getConnection()``. The DBAL
|
||||
configuration is explained in the
|
||||
The ``$connection`` passed as the first argument to he constructor of
|
||||
``EntityManager`` has to be an instance of ``Doctrine\DBAL\Connection``.
|
||||
You can use the factory ``Doctrine\DBAL\DriverManager::getConnection()``
|
||||
to create such a connection. The DBAL configuration is explained in the
|
||||
`DBAL section <https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/configuration.html>`_.
|
||||
|
||||
Proxy Objects
|
||||
@@ -311,10 +311,12 @@ Reference Proxies
|
||||
|
||||
The method ``EntityManager#getReference($entityName, $identifier)``
|
||||
lets you obtain a reference to an entity for which the identifier
|
||||
is known, without loading that entity from the database. This is
|
||||
useful, for example, as a performance enhancement, when you want to
|
||||
establish an association to an entity for which you have the
|
||||
identifier. You could simply do this:
|
||||
is known, without necessarily loading that entity from the database.
|
||||
This is useful, for example, as a performance enhancement, when you
|
||||
want to establish an association to an entity for which you have the
|
||||
identifier.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -324,14 +326,33 @@ identifier. You could simply do this:
|
||||
$item = $em->getReference('MyProject\Model\Item', $itemId);
|
||||
$cart->addItem($item);
|
||||
|
||||
Here, we added an Item to a Cart without loading the Item from the
|
||||
database. If you invoke any method on the Item instance, it would
|
||||
fully initialize its state transparently from the database. Here
|
||||
$item is actually an instance of the proxy class that was generated
|
||||
for the Item class but your code does not need to care. In fact it
|
||||
**should not care**. Proxy objects should be transparent to your
|
||||
Whether the object being returned from ``EntityManager#getReference()``
|
||||
is a proxy or a direct instance of the entity class may depend on different
|
||||
factors, including whether the entity has already been loaded into memory
|
||||
or entity inheritance being used. But your code does not need to care
|
||||
and in fact it **should not care**. Proxy objects should be transparent to your
|
||||
code.
|
||||
|
||||
When using the ``EntityManager#getReference()`` method, you need to be aware
|
||||
of a few peculiarities.
|
||||
|
||||
At the best case, the ORM can avoid querying the database at all. But, that
|
||||
also means that this method will not throw an exception when an invalid value
|
||||
for the ``$identifier`` parameter is passed. ``$identifier`` values are
|
||||
not checked and there is no guarantee that the requested entity instance even
|
||||
exists – the method will still return a proxy object.
|
||||
|
||||
Its only when the proxy has to be fully initialized or associations cannot
|
||||
be written to the database that invalid ``$identifier`` values may lead to
|
||||
exceptions.
|
||||
|
||||
The ``EntityManager#getReference()`` is mostly useful when you only
|
||||
need a reference to some entity to make an association, like in the example
|
||||
above. In that case, it can save you from loading data from the database
|
||||
that you don't need. But remember – as soon as you read any property values
|
||||
besides those making up the ID, a database request will be made to initialize
|
||||
all fields.
|
||||
|
||||
Association proxies
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -387,7 +408,7 @@ means that you have to register a special autoloader for these classes:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\Common\Proxy\Autoloader;
|
||||
use Doctrine\ORM\Proxy\Autoloader;
|
||||
|
||||
$proxyDir = "/path/to/proxies";
|
||||
$proxyNamespace = "MyProxies";
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
Annotations Reference
|
||||
=====================
|
||||
|
||||
.. warning::
|
||||
The annotation driver is deprecated and will be removed in version
|
||||
3.0. It is strongly recommended to switch to one of the other
|
||||
mapping drivers.
|
||||
|
||||
.. note::
|
||||
|
||||
To be able to use annotations, you will have to install an extra
|
||||
@@ -124,7 +129,7 @@ Optional attributes:
|
||||
- **nullable**: Determines if NULL values allowed for this column. If not specified, default value is false.
|
||||
|
||||
- **insertable**: Boolean value to determine if the column should be
|
||||
included when inserting a new row into the underlying entities table.
|
||||
included when inserting a new row into the underlying entities table.
|
||||
If not specified, default value is true.
|
||||
|
||||
- **updatable**: Boolean value to determine if the column should be
|
||||
@@ -540,12 +545,12 @@ has meaning in the SchemaTool schema generation context.
|
||||
Required attributes:
|
||||
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **fields**: Array of fields. Exactly one of **fields**, **columns** is required.
|
||||
- **columns**: Array of columns. Exactly one of **fields**, **columns** is required.
|
||||
|
||||
Optional attributes:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
@@ -1311,12 +1316,12 @@ context.
|
||||
Required attributes:
|
||||
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **fields**: Array of fields. Exactly one of **fields**, **columns** is required.
|
||||
- **columns**: Array of columns. Exactly one of **fields**, **columns** is required.
|
||||
|
||||
Optional attributes:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
@@ -1382,4 +1387,3 @@ Example:
|
||||
* @Version
|
||||
*/
|
||||
protected $version;
|
||||
|
||||
|
||||
@@ -24,28 +24,34 @@ performance it is also recommended that you use APC with PHP.
|
||||
Doctrine ORM Packages
|
||||
-------------------
|
||||
|
||||
Doctrine ORM is divided into three main packages.
|
||||
Doctrine ORM is divided into four main packages.
|
||||
|
||||
- Common
|
||||
- DBAL (includes Common)
|
||||
- ORM (includes DBAL+Common)
|
||||
- `Collections <https://www.doctrine-project.org/projects/doctrine-collections/en/stable/index.html>`_
|
||||
- `Event Manager <https://www.doctrine-project.org/projects/doctrine-event-manager/en/stable/index.html>`_
|
||||
- `Persistence <https://www.doctrine-project.org/projects/doctrine-persistence/en/stable/index.html>`_
|
||||
- `DBAL <https://www.doctrine-project.org/projects/doctrine-dbal/en/stable/index.html>`_
|
||||
- ORM (depends on DBAL+Persistence+Collections)
|
||||
|
||||
This manual mainly covers the ORM package, sometimes touching parts
|
||||
of the underlying DBAL and Common packages. The Doctrine code base
|
||||
of the underlying DBAL and Persistence packages. The Doctrine code base
|
||||
is split in to these packages for a few reasons and they are to...
|
||||
|
||||
|
||||
- ...make things more maintainable and decoupled
|
||||
- ...allow you to use the code in Doctrine Common without the ORM
|
||||
or DBAL
|
||||
- ...allow you to use the code in Doctrine Persistence and Collections
|
||||
without the ORM or DBAL
|
||||
- ...allow you to use the DBAL without the ORM
|
||||
|
||||
The Common Package
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
Collection, Event Manager and Persistence
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Common package contains highly reusable components that have no
|
||||
dependencies beyond the package itself (and PHP, of course). The
|
||||
root namespace of the Common package is ``Doctrine\Common``.
|
||||
The Collection, Event Manager and Persistence packages contain highly
|
||||
reusable components that have no dependencies beyond the packages
|
||||
themselves (and PHP, of course). The root namespace of the Persistence
|
||||
package is ``Doctrine\Persistence``. The root namespace of the
|
||||
Collection package is ``Doctrine\Common\Collections``, for historical
|
||||
reasons. The root namespace of the Event Manager package is just
|
||||
``Doctrine\Common``, also for historical reasons.
|
||||
|
||||
The DBAL Package
|
||||
~~~~~~~~~~~~~~~~
|
||||
@@ -74,32 +80,13 @@ Entities
|
||||
An entity is a lightweight, persistent domain object. An entity can
|
||||
be any regular PHP class observing the following restrictions:
|
||||
|
||||
|
||||
- An entity class must not be final or contain final methods.
|
||||
- All persistent properties/field of any entity class should
|
||||
always be private or protected, otherwise lazy-loading might not
|
||||
work as expected. In case you serialize entities (for example Session)
|
||||
properties should be protected (See Serialize section below).
|
||||
- An entity class must not implement ``__clone`` or
|
||||
:doc:`do so safely <../cookbook/implementing-wakeup-or-clone>`.
|
||||
- An entity class must not implement ``__wakeup`` or
|
||||
:doc:`do so safely <../cookbook/implementing-wakeup-or-clone>`.
|
||||
You can also consider implementing
|
||||
`Serializable <https://php.net/manual/en/class.serializable.php>`_,
|
||||
but be aware that it is deprecated since PHP 8.1. We do not recommend its usage.
|
||||
- PHP 7.4 introduces :doc:`the new magic method <https://php.net/manual/en/language.oop5.magic.php#object.unserialize>`
|
||||
``__unserialize``, which changes the execution priority between
|
||||
``__wakeup`` and itself when used. This can cause unexpected behaviour in
|
||||
an Entity.
|
||||
- An entity class must not be final nor read-only but
|
||||
it may contain final methods or read-only properties.
|
||||
- Any two entity classes in a class hierarchy that inherit
|
||||
directly or indirectly from one another must not have a mapped
|
||||
property with the same name. That is, if B inherits from A then B
|
||||
must not have a mapped field with the same name as an already
|
||||
mapped field that is inherited from A.
|
||||
- An entity cannot make use of func_get_args() to implement variable parameters.
|
||||
Generated proxies do not support this for performance reasons and your code might
|
||||
actually fail to work when violating this restriction.
|
||||
- Entity cannot access private/protected properties/methods of another entity of the same class or :doc:`do so safely <../cookbook/accessing-private-properties-of-the-same-class-from-different-instance>`.
|
||||
|
||||
Entities support inheritance, polymorphic associations, and
|
||||
polymorphic queries. Both abstract and concrete classes can be
|
||||
@@ -113,6 +100,25 @@ classes, and non-entity classes may extend entity classes.
|
||||
never calls entity constructors, thus you are free to use them as
|
||||
you wish and even have it require arguments of any type.
|
||||
|
||||
Mapped Superclasses
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A mapped superclass is an abstract or concrete class that provides
|
||||
persistent entity state and mapping information for its subclasses,
|
||||
but which is not itself an entity.
|
||||
|
||||
Mapped superclasses are explained in greater detail in the chapter
|
||||
on :doc:`inheritance mapping </reference/inheritance-mapping>`.
|
||||
|
||||
Transient Classes
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The term "transient class" appears in some places in the mapping
|
||||
drivers as well as the code dealing with metadata handling.
|
||||
|
||||
A transient class is a class that is neither an entity nor a mapped
|
||||
superclass. From the ORM's point of view, these classes can be
|
||||
completely ignored, and no class metadata is loaded for them at all.
|
||||
|
||||
Entity states
|
||||
~~~~~~~~~~~~~
|
||||
@@ -159,17 +165,13 @@ Serializing entities
|
||||
|
||||
Serializing entities can be problematic and is not really
|
||||
recommended, at least not as long as an entity instance still holds
|
||||
references to proxy objects or is still managed by an
|
||||
EntityManager. If you intend to serialize (and unserialize) entity
|
||||
instances that still hold references to proxy objects you may run
|
||||
into problems with private properties because of technical
|
||||
limitations. Proxy objects implement ``__sleep`` and it is not
|
||||
possible for ``__sleep`` to return names of private properties in
|
||||
parent classes. On the other hand it is not a solution for proxy
|
||||
objects to implement ``Serializable`` because Serializable does not
|
||||
work well with any potential cyclic object references (at least we
|
||||
did not find a way yet, if you did, please contact us). The
|
||||
``Serializable`` interface is also deprecated beginning with PHP 8.1.
|
||||
references to proxy objects or is still managed by an EntityManager.
|
||||
By default, serializing proxy objects does not initialize them. On
|
||||
unserialization, resulting objects are detached from the entity
|
||||
manager and cannot be initialiazed anymore. You can implement the
|
||||
``__serialize()`` method if you want to change that behavior, but
|
||||
then you need to ensure that you won't generate large serialized
|
||||
object graphs and take care of circular associations.
|
||||
|
||||
The EntityManager
|
||||
~~~~~~~~~~~~~~~~~
|
||||
@@ -203,5 +205,3 @@ typical implementation of the
|
||||
to keep track of all the things that need to be done the next time
|
||||
``flush`` is invoked. You usually do not directly interact with a
|
||||
``UnitOfWork`` but with the ``EntityManager`` instead.
|
||||
|
||||
|
||||
|
||||
@@ -881,6 +881,15 @@ Generated MySQL Schema:
|
||||
replaced by one-to-many/many-to-one associations between the 3
|
||||
participating classes.
|
||||
|
||||
.. note::
|
||||
|
||||
For many-to-many associations, the ORM takes care of managing rows
|
||||
in the join table connecting both sides. Due to the way it deals
|
||||
with entity removals, database-level constraints may not work the
|
||||
way one might intuitively assume. Thus, be sure not to miss the section
|
||||
on :ref:`join table management <remove_object_many_to_many_join_tables>`.
|
||||
|
||||
|
||||
Many-To-Many, Bidirectional
|
||||
---------------------------
|
||||
|
||||
@@ -1019,6 +1028,15 @@ one is bidirectional.
|
||||
The MySQL schema is exactly the same as for the Many-To-Many
|
||||
uni-directional case above.
|
||||
|
||||
.. note::
|
||||
|
||||
For many-to-many associations, the ORM takes care of managing rows
|
||||
in the join table connecting both sides. Due to the way it deals
|
||||
with entity removals, database-level constraints may not work the
|
||||
way one might intuitively assume. Thus, be sure not to miss the section
|
||||
on :ref:`join table management <remove_object_many_to_many_join_tables>`.
|
||||
|
||||
|
||||
Owning and Inverse Side on a ManyToMany Association
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -1282,8 +1300,8 @@ This is essentially the same as the following, more verbose, mapping:
|
||||
* @var Collection<int, Group>
|
||||
*/
|
||||
#[JoinTable(name: 'User_Group')]
|
||||
#[JoinColumn(name: 'User_id', referencedColumnName: 'id')]
|
||||
#[InverseJoinColumn(name: 'Group_id', referencedColumnName: 'id')]
|
||||
#[JoinColumn(name: 'user_id', referencedColumnName: 'id')]
|
||||
#[InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')]
|
||||
#[ManyToMany(targetEntity: Group::class)]
|
||||
private Collection $groups;
|
||||
// ...
|
||||
@@ -1315,10 +1333,10 @@ This is essentially the same as the following, more verbose, mapping:
|
||||
<many-to-many field="groups" target-entity="Group">
|
||||
<join-table name="User_Group">
|
||||
<join-columns>
|
||||
<join-column id="User_id" referenced-column-name="id" />
|
||||
<join-column id="user_id" referenced-column-name="id" />
|
||||
</join-columns>
|
||||
<inverse-join-columns>
|
||||
<join-column id="Group_id" referenced-column-name="id" />
|
||||
<join-column id="group_id" referenced-column-name="id" />
|
||||
</inverse-join-columns>
|
||||
</join-table>
|
||||
</many-to-many>
|
||||
@@ -1350,8 +1368,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::
|
||||
|
||||
@@ -1386,24 +1403,24 @@ Is essentially the same as following:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
/** One Product has One Shipment. */
|
||||
#[OneToOne(targetEntity: Shipment::class)]
|
||||
#[JoinColumn(name: 'shipment_id', referencedColumnName: 'id')]
|
||||
private Shipment $shipment;
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/**
|
||||
* 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;
|
||||
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
/** One Product has One Shipment. */
|
||||
#[OneToOne(targetEntity: Shipment::class)]
|
||||
#[JoinColumn(name: 'shipment_id', referencedColumnName: 'id', nullable: false)]
|
||||
private Shipment $shipment;
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping>
|
||||
@@ -1424,7 +1441,6 @@ Is essentially the same as following:
|
||||
joinColumn:
|
||||
name: shipment_id
|
||||
referencedColumnName: id
|
||||
nullable: false
|
||||
|
||||
If you accept these defaults, you can reduce the mapping code to a
|
||||
minimum.
|
||||
|
||||
@@ -14,7 +14,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>`
|
||||
@@ -366,6 +366,9 @@ 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.
|
||||
- **enumType**: By default this is `null`. Allows to map discriminatorColumn value to PHP enum
|
||||
- **options**: See "options" attribute on :ref:`#[Column] <attrref_column>`.
|
||||
|
||||
.. _attrref_discriminatormap:
|
||||
|
||||
@@ -537,13 +540,13 @@ has meaning in the ``SchemaTool`` schema generation context.
|
||||
|
||||
Required parameters:
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **fields**: Array of fields. Exactly one of **fields, columns** is required.
|
||||
- **columns**: Array of columns. Exactly one of **fields, columns** is required.
|
||||
|
||||
|
||||
Optional parameters:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
@@ -573,7 +576,7 @@ Example with partial indexes:
|
||||
|
||||
#[Index(name: "search_idx", columns: ["category"],
|
||||
options: [
|
||||
"where": "((category IS NOT NULL))"
|
||||
"where" => "((category IS NOT NULL))"
|
||||
]
|
||||
)]
|
||||
class ECommerceProduct
|
||||
@@ -1101,11 +1104,12 @@ context.
|
||||
|
||||
Required parameters:
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **columns**: Array of columns.
|
||||
- **fields**: Array of fields (the names of the properties, used in the entity class).
|
||||
- **columns**: Array of columns (the names of the columns, used in the schema).
|
||||
|
||||
Optional parameters:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
|
||||
@@ -45,9 +45,9 @@ Doctrine provides several different ways to specify object-relational
|
||||
mapping metadata:
|
||||
|
||||
- :doc:`Attributes <attributes-reference>`
|
||||
- :doc:`Docblock Annotations <annotations-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
|
||||
@@ -239,6 +239,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),
|
||||
@@ -288,55 +289,24 @@ These are the "automatic" mapping rules:
|
||||
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``.
|
||||
|
||||
.. versionadded:: 2.14
|
||||
|
||||
Since version 2.14 you can specify custom typed field mapping between PHP type and DBAL type using ``Configuration``
|
||||
and a custom ``Doctrine\ORM\Mapping\TypedFieldMapper`` implementation.
|
||||
|
||||
:doc:`Read more about TypedFieldMapper <typedfieldmapper>`.
|
||||
|
||||
.. _reference-mapping-types:
|
||||
|
||||
Doctrine Mapping Types
|
||||
----------------------
|
||||
|
||||
The ``type`` option used in the ``@Column`` accepts any of the existing
|
||||
Doctrine types or even your own custom types. A Doctrine type defines
|
||||
The ``type`` option used in the ``@Column`` accepts any of the
|
||||
`existing Doctrine DBAL types <https://docs.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/types.html#reference>`_
|
||||
or :doc:`your own custom mapping types
|
||||
<../cookbook/custom-mapping-types>`. A Doctrine type defines
|
||||
the conversion between PHP and SQL types, independent from the database vendor
|
||||
you are using. All Mapping Types that ship with Doctrine are fully portable
|
||||
between the supported database systems.
|
||||
|
||||
As an example, the Doctrine Mapping Type ``string`` defines the
|
||||
mapping from a PHP string to a SQL VARCHAR (or VARCHAR2 etc.
|
||||
depending on the RDBMS brand). Here is a quick overview of the
|
||||
built-in mapping types:
|
||||
|
||||
- ``string``: Type that maps a SQL VARCHAR to a PHP string.
|
||||
- ``integer``: Type that maps a SQL INT to a PHP integer.
|
||||
- ``smallint``: Type that maps a database SMALLINT to a PHP
|
||||
integer.
|
||||
- ``bigint``: Type that maps a database BIGINT to a PHP string.
|
||||
- ``boolean``: Type that maps a SQL boolean or equivalent (TINYINT) to a PHP boolean.
|
||||
- ``decimal``: Type that maps a SQL DECIMAL to a PHP string.
|
||||
- ``date``: Type that maps a SQL DATETIME to a PHP DateTime
|
||||
object.
|
||||
- ``time``: Type that maps a SQL TIME to a PHP DateTime object.
|
||||
- ``datetime``: Type that maps a SQL DATETIME/TIMESTAMP to a PHP
|
||||
DateTime object.
|
||||
- ``datetimetz``: Type that maps a SQL DATETIME/TIMESTAMP to a PHP
|
||||
DateTime object with timezone.
|
||||
- ``text``: Type that maps a SQL CLOB to a PHP string.
|
||||
- ``object``: Type that maps a SQL CLOB to a PHP object using
|
||||
``serialize()`` and ``unserialize()``
|
||||
- ``array``: Type that maps a SQL CLOB to a PHP array using
|
||||
``serialize()`` and ``unserialize()``
|
||||
- ``simple_array``: Type that maps a SQL CLOB to a PHP array using
|
||||
``implode()`` and ``explode()``, with a comma as delimiter. *IMPORTANT*
|
||||
Only use this type if you are sure that your values cannot contain a ",".
|
||||
- ``json_array``: Type that maps a SQL CLOB to a PHP array using
|
||||
``json_encode()`` and ``json_decode()``
|
||||
- ``float``: Type that maps a SQL Float (Double Precision) to a
|
||||
PHP double. *IMPORTANT*: Works only with locale settings that use
|
||||
decimal points as separator.
|
||||
- ``guid``: Type that maps a database GUID/UUID to a PHP string. Defaults to
|
||||
varchar but uses a specific type if the platform supports it.
|
||||
- ``blob``: Type that maps a SQL BLOB to a PHP resource stream
|
||||
|
||||
A cookbook article shows how to define :doc:`your own custom mapping types
|
||||
<../cookbook/custom-mapping-types>`.
|
||||
you are using.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -415,9 +385,11 @@ the field that serves as the identifier with the ``#[Id]`` attribute.
|
||||
# fields here
|
||||
|
||||
In most cases using the automatic generator strategy (``#[GeneratedValue]``) is
|
||||
what you want. It defaults to the identifier generation mechanism your current
|
||||
database vendor prefers: AUTO_INCREMENT with MySQL, sequences with PostgreSQL
|
||||
and Oracle and so on.
|
||||
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.
|
||||
|
||||
.. _identifier-generation-strategies:
|
||||
|
||||
@@ -434,17 +406,18 @@ Here is the list of possible generation strategies:
|
||||
|
||||
- ``AUTO`` (default): Tells Doctrine to pick the strategy that is
|
||||
preferred by the used database platform. The preferred strategies
|
||||
are IDENTITY for MySQL, SQLite, MsSQL and SQL Anywhere and SEQUENCE
|
||||
for Oracle and PostgreSQL. This strategy provides full portability.
|
||||
- ``SEQUENCE``: Tells Doctrine to use a database sequence for ID
|
||||
generation. This strategy does currently not provide full
|
||||
portability. Sequences are supported by Oracle, PostgreSql and
|
||||
SQL Anywhere.
|
||||
are ``IDENTITY`` for MySQL, SQLite, MsSQL and SQL Anywhere and, for
|
||||
historical reasons, ``SEQUENCE`` for Oracle and PostgreSQL. This
|
||||
strategy provides full portability.
|
||||
- ``IDENTITY``: Tells Doctrine to use special identity columns in
|
||||
the database that generate a value on insertion of a row. This
|
||||
strategy does currently not provide full portability and is
|
||||
supported by the following platforms: MySQL/SQLite/SQL Anywhere
|
||||
(AUTO\_INCREMENT), MSSQL (IDENTITY) and PostgreSQL (SERIAL).
|
||||
(``AUTO_INCREMENT``), MSSQL (``IDENTITY``) and PostgreSQL (``SERIAL``).
|
||||
- ``SEQUENCE``: Tells Doctrine to use a database sequence for ID
|
||||
generation. This strategy does currently not provide full
|
||||
portability. Sequences are supported by Oracle, PostgreSql and
|
||||
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
|
||||
@@ -452,7 +425,7 @@ Here is the list of possible generation strategies:
|
||||
a new entity is passed to ``EntityManager#persist``. NONE is the
|
||||
same as leaving off the ``#[GeneratedValue]`` entirely.
|
||||
- ``CUSTOM``: With this option, you can use the ``#[CustomIdGenerator]`` attribute.
|
||||
It will allow you to pass a :doc:`class of your own to generate the identifiers.<_annref_customidgenerator>`
|
||||
It will allow you to pass a :ref:`class of your own to generate the identifiers. <annref_customidgenerator>`
|
||||
|
||||
Sequence Generator
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
@@ -526,8 +499,6 @@ the above example with ``allocationSize=100`` Doctrine ORM would only
|
||||
need to access the sequence once to generate the identifiers for
|
||||
100 new entities.
|
||||
|
||||
*The default allocationSize for a @SequenceGenerator is currently 10.*
|
||||
|
||||
.. caution::
|
||||
|
||||
The allocationSize is detected by SchemaTool and
|
||||
|
||||
@@ -18,8 +18,16 @@ especially what the strategies presented here provide help with.
|
||||
|
||||
.. note::
|
||||
|
||||
Having an SQL logger enabled when processing batches can have a serious impact on performance and resource usage.
|
||||
To avoid that you should disable it in the DBAL configuration:
|
||||
Having an SQL logger enabled when processing batches can have a
|
||||
serious impact on performance and resource usage.
|
||||
To avoid that, you should use a PSR logger implementation that can be
|
||||
disabled at runtime.
|
||||
For example, with Monolog, you can use ``Logger::pushHandler()``
|
||||
to push a ``NullHandler`` to the logger instance, and then pop it
|
||||
when you need to enable logging again.
|
||||
|
||||
With DBAL 2, you can disable the SQL logger like below:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
@@ -84,7 +92,7 @@ with the batching strategy that was already used for bulk inserts:
|
||||
|
||||
<?php
|
||||
$batchSize = 20;
|
||||
$i = 1;
|
||||
$i = 0;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
foreach ($q->toIterable() as $user) {
|
||||
$user->increaseCredit();
|
||||
@@ -143,7 +151,7 @@ The following example shows how to do this:
|
||||
|
||||
<?php
|
||||
$batchSize = 20;
|
||||
$i = 1;
|
||||
$i = 0;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
foreach($q->toIterable() as $row) {
|
||||
$em->remove($row);
|
||||
@@ -186,6 +194,3 @@ problems using the following approach:
|
||||
Iterating results is not possible with queries that
|
||||
fetch-join a collection-valued association. The nature of such SQL
|
||||
result sets is not suitable for incremental hydration.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ Notify
|
||||
.. note::
|
||||
|
||||
The notify change tracking policy is deprecated and will be removed in ORM 3.0.
|
||||
(`Details <https://github.com/doctrine/orm/issues/8383>`_)
|
||||
(\ `Details <https://github.com/doctrine/orm/issues/8383>`_)
|
||||
|
||||
This policy is based on the assumption that the entities notify
|
||||
interested listeners of changes to their properties. For that
|
||||
|
||||
@@ -41,22 +41,24 @@ access point to ORM functionality provided by Doctrine.
|
||||
// bootstrap.php
|
||||
require_once "vendor/autoload.php";
|
||||
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\ORMSetup;
|
||||
|
||||
$paths = array("/path/to/entity-files");
|
||||
$paths = ['/path/to/entity-files'];
|
||||
$isDevMode = false;
|
||||
|
||||
// the connection configuration
|
||||
$dbParams = array(
|
||||
$dbParams = [
|
||||
'driver' => 'pdo_mysql',
|
||||
'user' => 'root',
|
||||
'password' => '',
|
||||
'dbname' => 'foo',
|
||||
);
|
||||
];
|
||||
|
||||
$config = ORMSetup::createAttributeMetadataConfiguration($paths, $isDevMode);
|
||||
$entityManager = EntityManager::create($dbParams, $config);
|
||||
$connection = DriverManager::getConnection($dbParams, $config);
|
||||
$entityManager = new EntityManager($connection, $config);
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -68,18 +70,20 @@ Or if you prefer XML:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$paths = array("/path/to/xml-mappings");
|
||||
$paths = ['/path/to/xml-mappings'];
|
||||
$config = ORMSetup::createXMLMetadataConfiguration($paths, $isDevMode);
|
||||
$entityManager = EntityManager::create($dbParams, $config);
|
||||
$connection = DriverManager::getConnection($dbParams, $config);
|
||||
$entityManager = new EntityManager($connection, $config);
|
||||
|
||||
Or if you prefer YAML:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$paths = array("/path/to/yml-mappings");
|
||||
$paths = ['/path/to/yml-mappings'];
|
||||
$config = ORMSetup::createYAMLMetadataConfiguration($paths, $isDevMode);
|
||||
$entityManager = EntityManager::create($dbParams, $config);
|
||||
$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`:
|
||||
@@ -100,7 +104,7 @@ Inside the ``ORMSetup`` methods several assumptions are made:
|
||||
In order to have ``ORMSetup`` configure the cache automatically, the library ``symfony/cache``
|
||||
has to be installed as a dependency.
|
||||
|
||||
If you want to configure Doctrine in more detail, take a look at the :doc:`Advanced Configuration <reference/advanced-configuration>` section.
|
||||
If you want to configure Doctrine in more detail, take a look at the :doc:`Advanced Configuration </reference/advanced-configuration>` section.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
@@ -180,10 +180,10 @@ not need to lazy load the association with another query.
|
||||
|
||||
Doctrine allows you to walk all the associations between
|
||||
all the objects in your domain model. Objects that were not already
|
||||
loaded from the database are replaced with lazy load proxy
|
||||
instances. Non-loaded Collections are also replaced by lazy-load
|
||||
loaded from the database are replaced with lazy-loading proxy
|
||||
instances. Non-loaded Collections are also replaced by lazy-loading
|
||||
instances that fetch all the contained objects upon first access.
|
||||
However relying on the lazy-load mechanism leads to many small
|
||||
However relying on the lazy-loading mechanism leads to many small
|
||||
queries executed against the database, which can significantly
|
||||
affect the performance of your application. **Fetch Joins** are the
|
||||
solution to hydrate most or all of the entities that you need in a
|
||||
@@ -319,11 +319,11 @@ With Nested Conditions in WHERE Clause:
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM ForumUser u WHERE (u.username = :name OR u.username = :name2) AND u.id = :id');
|
||||
$query->setParameters(array(
|
||||
$query->setParameters([
|
||||
'name' => 'Bob',
|
||||
'name2' => 'Alice',
|
||||
'id' => 321,
|
||||
));
|
||||
]);
|
||||
$users = $query->getResult(); // array of ForumUser objects
|
||||
|
||||
With COUNT DISTINCT:
|
||||
@@ -464,6 +464,11 @@ hierarchies:
|
||||
$query = $em->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyEmployee');
|
||||
$query = $em->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF ?1');
|
||||
$query = $em->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u NOT INSTANCE OF ?1');
|
||||
$query->setParameter(0, $em->getClassMetadata(CompanyEmployee::class));
|
||||
|
||||
.. note::
|
||||
To use a class as parameter, you have to bind its class metadata:
|
||||
``$query->setParameter(0, $em->getClassMetadata(CompanyEmployee::class);``.
|
||||
|
||||
Get all users visible on a given website that have chosen certain gender:
|
||||
|
||||
@@ -794,7 +799,7 @@ You can register custom DQL functions in your ORM Configuration:
|
||||
$config->addCustomNumericFunction($name, $class);
|
||||
$config->addCustomDatetimeFunction($name, $class);
|
||||
|
||||
$em = EntityManager::create($dbParams, $config);
|
||||
$em = new EntityManager($connection, $config);
|
||||
|
||||
The functions have to return either a string, numeric or datetime
|
||||
value depending on the registered function type. As an example we
|
||||
@@ -806,8 +811,8 @@ classes have to implement the base class :
|
||||
<?php
|
||||
namespace MyProject\Query\AST;
|
||||
|
||||
use \Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use \Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
class MysqlFloor extends FunctionNode
|
||||
{
|
||||
@@ -822,12 +827,12 @@ classes have to implement the base class :
|
||||
|
||||
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,7 +1003,7 @@ The Query class
|
||||
---------------
|
||||
|
||||
An instance of the ``Doctrine\ORM\Query`` class represents a DQL
|
||||
query. You create a Query instance be calling
|
||||
query. You create a Query instance by calling
|
||||
``EntityManager#createQuery($dql)``, passing the DQL query string.
|
||||
Alternatively you can create an empty ``Query`` instance and invoke
|
||||
``Query#setDQL($dql)`` afterwards. Here are some examples:
|
||||
@@ -1015,58 +1020,146 @@ Alternatively you can create an empty ``Query`` instance and invoke
|
||||
$q = $em->createQuery();
|
||||
$q->setDQL('select u from MyProject\Model\User u');
|
||||
|
||||
Query Result Formats
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
Query Result Formats (Hydration Modes)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The format in which the result of a DQL SELECT query is returned
|
||||
can be influenced by a so-called ``hydration mode``. A hydration
|
||||
mode specifies a particular way in which a SQL result set is
|
||||
transformed. Each hydration mode has its own dedicated method on
|
||||
the Query class. Here they are:
|
||||
The way in which the SQL result set of a DQL SELECT query is transformed
|
||||
to PHP is determined by the so-called "hydration mode".
|
||||
|
||||
``getResult()``
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
- ``Query#getResult()``: Retrieves a collection of objects. The
|
||||
result is either a plain collection of objects (pure) or an array
|
||||
where the objects are nested in the result rows (mixed).
|
||||
- ``Query#getSingleResult()``: Retrieves a single object. If the
|
||||
result contains more than one object, an ``NonUniqueResultException``
|
||||
is thrown. If the result contains no objects, an ``NoResultException``
|
||||
is thrown. The pure/mixed distinction does not apply.
|
||||
- ``Query#getOneOrNullResult()``: Retrieve a single object. If the
|
||||
result contains more than one object, a ``NonUniqueResultException``
|
||||
is thrown. If no object is found null will be returned.
|
||||
- ``Query#getArrayResult()``: Retrieves an array graph (a nested
|
||||
array) that is largely interchangeable with the object graph
|
||||
generated by ``Query#getResult()`` for read-only purposes.
|
||||
Retrieves a collection of objects. The result is either a plain collection of objects (pure) or an array
|
||||
where the objects are nested in the result rows (mixed):
|
||||
|
||||
.. note::
|
||||
.. code-block:: php
|
||||
|
||||
An array graph can differ from the corresponding object
|
||||
graph in certain scenarios due to the difference of the identity
|
||||
semantics between arrays and objects.
|
||||
<?php
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
|
||||
$query = $em->createQuery('SELECT u FROM User u');
|
||||
$users = $query->getResult();
|
||||
// same as:
|
||||
$users = $query->getResult(AbstractQuery::HYDRATE_OBJECT);
|
||||
|
||||
- Objects fetched in a FROM clause are returned as a Set, that means every
|
||||
object is only ever included in the resulting array once. This is the case
|
||||
even when using JOIN or GROUP BY in ways that return the same row for an
|
||||
object multiple times. If the hydrator sees the same object multiple times,
|
||||
then it makes sure it is only returned once.
|
||||
|
||||
- ``Query#getScalarResult()``: Retrieves a flat/rectangular result
|
||||
set of scalar values that can contain duplicate data. The
|
||||
pure/mixed distinction does not apply.
|
||||
- ``Query#getSingleScalarResult()``: Retrieves a single scalar
|
||||
value from the result returned by the dbms. If the result contains
|
||||
more than a single scalar value, an exception is thrown. The
|
||||
pure/mixed distinction does not apply.
|
||||
- If an object is already in memory from a previous query of any kind, then
|
||||
then the previous object is used, even if the database may contain more
|
||||
recent data. This even happens if the previous object is still an unloaded proxy.
|
||||
|
||||
Instead of using these methods, you can alternatively use the
|
||||
general-purpose method
|
||||
``Query#execute(array $params = array(), $hydrationMode = Query::HYDRATE_OBJECT)``.
|
||||
Using this method you can directly supply the hydration mode as the
|
||||
second parameter via one of the Query constants. In fact, the
|
||||
methods mentioned earlier are just convenient shortcuts for the
|
||||
execute method. For example, the method ``Query#getResult()``
|
||||
internally invokes execute, passing in ``Query::HYDRATE_OBJECT`` as
|
||||
the hydration mode.
|
||||
``getArrayResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The use of the methods mentioned earlier is generally preferred as
|
||||
it leads to more concise code.
|
||||
Retrieves an array graph (a nested array) for read-only purposes.
|
||||
|
||||
.. note::
|
||||
|
||||
An array graph can differ from the corresponding object
|
||||
graph in certain scenarios due to the difference of the identity
|
||||
semantics between arrays and objects.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$users = $query->getArrayResult();
|
||||
// same as:
|
||||
$users = $query->getResult(AbstractQuery::HYDRATE_ARRAY);
|
||||
|
||||
``getScalarResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieves a flat/rectangular result set of scalar values that can contain duplicate data. The
|
||||
pure/mixed distinction does not apply.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$users = $query->getScalarResult();
|
||||
// same as:
|
||||
$users = $query->getResult(AbstractQuery::HYDRATE_SCALAR);
|
||||
|
||||
Fields from classes are prefixed by the DQL alias in the result.
|
||||
A query of the kind `SELECT u.name ...` returns a key `u_name` in the result rows.
|
||||
|
||||
``getSingleScalarResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieves a single scalar value from the result returned by the database. If the result contains
|
||||
more than a single scalar value, a ``NonUniqueResultException`` is thrown. The pure/mixed distinction does not apply.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT COUNT(u.id) FROM User u');
|
||||
$numUsers = $query->getSingleScalarResult();
|
||||
// same as:
|
||||
$numUsers = $query->getResult(AbstractQuery::HYDRATE_SINGLE_SCALAR);
|
||||
|
||||
``getSingleColumnResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieves an array from a one-dimensional array of scalar values:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT a.id FROM User u');
|
||||
$ids = $query->getSingleColumnResult();
|
||||
// same as:
|
||||
$ids = $query->getResult(AbstractQuery::HYDRATE_SCALAR_COLUMN);
|
||||
|
||||
``getSingleResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieves a single object. If the result contains more than one object, a ``NonUniqueResultException``
|
||||
is thrown. If the result contains no objects, a ``NoResultException`` is thrown. The pure/mixed distinction does not apply.
|
||||
|
||||
``getOneOrNullResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieves a single object. If the result contains more than one object, a ``NonUniqueResultException``
|
||||
is thrown. If no object is found, ``null`` will be returned.
|
||||
|
||||
Custom Hydration Modes
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can easily add your own custom hydration modes by first
|
||||
creating a class which extends ``AbstractHydrator``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace MyProject\Hydrators;
|
||||
|
||||
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
|
||||
|
||||
class CustomHydrator extends AbstractHydrator
|
||||
{
|
||||
protected function _hydrateAll()
|
||||
{
|
||||
return $this->_stmt->fetchAllAssociative();
|
||||
}
|
||||
}
|
||||
|
||||
Next you just need to add the class to the ORM configuration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$em->getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator');
|
||||
|
||||
Now the hydrator is ready to be used in your queries:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u');
|
||||
$results = $query->getResult('CustomHydrator');
|
||||
|
||||
Pure and Mixed Results
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -1170,166 +1263,6 @@ will return the rows iterating the different top-level entities.
|
||||
[2] => Object (User)
|
||||
[3] => Object (Group)
|
||||
|
||||
|
||||
Hydration Modes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Each of the Hydration Modes makes assumptions about how the result
|
||||
is returned to user land. You should know about all the details to
|
||||
make best use of the different result formats:
|
||||
|
||||
The constants for the different hydration modes are:
|
||||
|
||||
|
||||
- ``Query::HYDRATE_OBJECT``
|
||||
- ``Query::HYDRATE_ARRAY``
|
||||
- ``Query::HYDRATE_SCALAR``
|
||||
- ``Query::HYDRATE_SINGLE_SCALAR``
|
||||
- ``Query::HYDRATE_SCALAR_COLUMN``
|
||||
|
||||
Object Hydration
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Object hydration hydrates the result set into the object graph:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u');
|
||||
$users = $query->getResult(Query::HYDRATE_OBJECT);
|
||||
|
||||
Sometimes the behavior in the object hydrator can be confusing, which is
|
||||
why we are listing as many of the assumptions here for reference:
|
||||
|
||||
- Objects fetched in a FROM clause are returned as a Set, that means every
|
||||
object is only ever included in the resulting array once. This is the case
|
||||
even when using JOIN or GROUP BY in ways that return the same row for an
|
||||
object multiple times. If the hydrator sees the same object multiple times,
|
||||
then it makes sure it is only returned once.
|
||||
|
||||
- If an object is already in memory from a previous query of any kind, then
|
||||
then the previous object is used, even if the database may contain more
|
||||
recent data. Data from the database is discarded. This even happens if the
|
||||
previous object is still an unloaded proxy.
|
||||
|
||||
This list might be incomplete.
|
||||
|
||||
Array Hydration
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
You can run the same query with array hydration and the result set
|
||||
is hydrated into an array that represents the object graph:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u');
|
||||
$users = $query->getResult(Query::HYDRATE_ARRAY);
|
||||
|
||||
You can use the ``getArrayResult()`` shortcut as well:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$users = $query->getArrayResult();
|
||||
|
||||
Scalar Hydration
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
If you want to return a flat rectangular result set instead of an
|
||||
object graph you can use scalar hydration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u');
|
||||
$users = $query->getResult(Query::HYDRATE_SCALAR);
|
||||
echo $users[0]['u_id'];
|
||||
|
||||
The following assumptions are made about selected fields using
|
||||
Scalar Hydration:
|
||||
|
||||
|
||||
1. Fields from classes are prefixed by the DQL alias in the result.
|
||||
A query of the kind 'SELECT u.name ..' returns a key 'u_name' in
|
||||
the result rows.
|
||||
|
||||
Single Scalar Hydration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you have a query which returns just a single scalar value you can use
|
||||
single scalar hydration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT COUNT(a.id) FROM CmsUser u LEFT JOIN u.articles a WHERE u.username = ?1 GROUP BY u.id');
|
||||
$query->setParameter(1, 'jwage');
|
||||
$numArticles = $query->getResult(Query::HYDRATE_SINGLE_SCALAR);
|
||||
|
||||
You can use the ``getSingleScalarResult()`` shortcut as well:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$numArticles = $query->getSingleScalarResult();
|
||||
|
||||
Scalar Column Hydration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you have a query which returns a one-dimensional array of scalar values
|
||||
you can use scalar column hydration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT a.id FROM CmsUser u');
|
||||
$ids = $query->getResult(Query::HYDRATE_SCALAR_COLUMN);
|
||||
|
||||
You can use the ``getSingleColumnResult()`` shortcut as well:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$ids = $query->getSingleColumnResult();
|
||||
|
||||
Custom Hydration Modes
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can easily add your own custom hydration modes by first
|
||||
creating a class which extends ``AbstractHydrator``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace MyProject\Hydrators;
|
||||
|
||||
use Doctrine\DBAL\FetchMode;
|
||||
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
|
||||
|
||||
class CustomHydrator extends AbstractHydrator
|
||||
{
|
||||
protected function _hydrateAll()
|
||||
{
|
||||
return $this->_stmt->fetchAll(FetchMode::FETCH_ASSOC);
|
||||
}
|
||||
}
|
||||
|
||||
Next you just need to add the class to the ORM configuration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$em->getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator');
|
||||
|
||||
Now the hydrator is ready to be used in your queries:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u');
|
||||
$results = $query->getResult('CustomHydrator');
|
||||
|
||||
Iterating Large Result Sets
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -1337,8 +1270,8 @@ There are situations when a query you want to execute returns a
|
||||
very large result-set that needs to be processed. All the
|
||||
previously described hydration modes completely load a result-set
|
||||
into memory which might not be feasible with large result sets. See
|
||||
the `Batch Processing <batch-processing.html>`_ section on details how
|
||||
to iterate large result sets.
|
||||
the :doc:`Batch Processing </reference/batch-processing>` section on
|
||||
details how to iterate large result sets.
|
||||
|
||||
Functions
|
||||
~~~~~~~~~
|
||||
@@ -1382,7 +1315,7 @@ Result Cache API:
|
||||
$query->setResultCacheDriver(new ApcCache());
|
||||
|
||||
$query->useResultCache(true)
|
||||
->setResultCacheLifeTime($seconds = 3600);
|
||||
->setResultCacheLifeTime(3600);
|
||||
|
||||
$result = $query->getResult(); // cache miss
|
||||
|
||||
@@ -1393,7 +1326,7 @@ Result Cache API:
|
||||
$result = $query->getResult(); // saved in given result cache id.
|
||||
|
||||
// or call useResultCache() with all parameters:
|
||||
$query->useResultCache(true, $seconds = 3600, 'my_query_result');
|
||||
$query->useResultCache(true, 3600, 'my_query_result');
|
||||
$result = $query->getResult(); // cache hit!
|
||||
|
||||
// Introspection
|
||||
@@ -1426,7 +1359,7 @@ userland:
|
||||
reloading this data. Partially loaded objects have to be passed to
|
||||
``EntityManager::refresh()`` if they are to be reloaded fully from
|
||||
the database. This query hint is deprecated and will be removed
|
||||
in the future (`Details <https://github.com/doctrine/orm/issues/8471>`_)
|
||||
in the future (\ `Details <https://github.com/doctrine/orm/issues/8471>`_)
|
||||
- ``Query::HINT_REFRESH`` - This query is used internally by
|
||||
``EntityManager::refresh()`` and can be used in userland as well.
|
||||
If you specify this hint and a query returns the data for an entity
|
||||
@@ -1458,7 +1391,7 @@ several methods to interact with it:
|
||||
|
||||
- ``Query::setQueryCacheDriver($driver)`` - Allows to set a Cache
|
||||
instance
|
||||
- ``Query::setQueryCacheLifeTime($seconds = 3600)`` - Set lifetime
|
||||
- ``Query::setQueryCacheLifeTime($seconds)`` - Set lifetime
|
||||
of the query caching.
|
||||
- ``Query::expireQueryCache($bool)`` - Enforce the expiring of the
|
||||
query cache if set to true.
|
||||
|
||||
@@ -131,47 +131,60 @@ There are two ways to set up an event handler:
|
||||
* For *all events* you can create a Lifecycle Event Listener or Subscriber class and register
|
||||
it by calling ``$eventManager->addEventListener()`` or ``eventManager->addEventSubscriber()``,
|
||||
see
|
||||
:ref:`Listening and subscribing to Lifecycle Events<listening-and-subscribing-to-lifecycle-events>`
|
||||
:ref:`Listening and subscribing to Lifecycle Events <listening-and-subscribing-to-lifecycle-events>`
|
||||
* For *some events* (see table below), you can create a *Lifecycle Callback* method in the
|
||||
entity, see :ref:`Lifecycle Callbacks<lifecycle-callbacks>`.
|
||||
entity, see :ref:`Lifecycle Callbacks <lifecycle-callbacks>`.
|
||||
|
||||
.. _reference-events-lifecycle-events:
|
||||
|
||||
Events Overview
|
||||
---------------
|
||||
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| Event | Dispatched by | Lifecycle | Passed |
|
||||
| | | Callback | Argument |
|
||||
+=================================================================+=======================+===========+=====================================+
|
||||
| :ref:`preRemove<reference-events-pre-remove>` | ``$em->remove()`` | Yes | `LifecycleEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postRemove<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `LifecycleEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`prePersist<reference-events-pre-persist>` | ``$em->persist()`` | Yes | `LifecycleEventArgs`_ |
|
||||
| | on *initial* persist | | |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postPersist<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `LifecycleEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preUpdate<reference-events-pre-update>` | ``$em->flush()`` | Yes | `PreUpdateEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postUpdate<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `LifecycleEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postLoad<reference-events-post-load>` | Loading from database | Yes | `LifecycleEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`loadClassMetadata<reference-events-load-class-metadata>` | Loading of mapping | No | `LoadClassMetadataEventArgs`_ |
|
||||
| | metadata | | |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| ``onClassMetadataNotFound`` | ``MappingException`` | No | `OnClassMetadataNotFoundEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preFlush<reference-events-pre-flush>` | ``$em->flush()`` | Yes | `PreFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onFlush<reference-events-on-flush>` | ``$em->flush()`` | No | `OnFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postFlush<reference-events-post-flush>` | ``$em->flush()`` | No | `PostFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onClear<reference-events-on-clear>` | ``$em->clear()`` | No | `OnClearEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| Event | Dispatched by | Lifecycle | Passed |
|
||||
| | | Callback | Argument |
|
||||
+==================================================================+=======================+===========+=====================================+
|
||||
| :ref:`preRemove <reference-events-pre-remove>` | ``$em->remove()`` | Yes | `PreRemoveEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postRemove <reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostRemoveEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`prePersist <reference-events-pre-persist>` | ``$em->persist()`` | Yes | `PrePersistEventArgs`_ |
|
||||
| | on *initial* persist | | |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postPersist <reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostPersistEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preUpdate <reference-events-pre-update>` | ``$em->flush()`` | Yes | `PreUpdateEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postUpdate <reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostUpdateEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postLoad <reference-events-post-load>` | Loading from database | Yes | `PostLoadEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`loadClassMetadata <reference-events-load-class-metadata>` | Loading of mapping | No | `LoadClassMetadataEventArgs`_ |
|
||||
| | metadata | | |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| ``onClassMetadataNotFound`` | ``MappingException`` | No | `OnClassMetadataNotFoundEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preFlush <reference-events-pre-flush>` | ``$em->flush()`` | Yes | `PreFlushEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onFlush <reference-events-on-flush>` | ``$em->flush()`` | No | `OnFlushEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postFlush <reference-events-post-flush>` | ``$em->flush()`` | No | `PostFlushEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onClear <reference-events-on-clear>` | ``$em->clear()`` | No | `OnClearEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
|
||||
.. warning::
|
||||
|
||||
Making changes to entities and calling ``EntityManager::flush()`` from within
|
||||
event handlers dispatched by ``EntityManager::flush()`` itself is strongly
|
||||
discouraged, and might be deprecated and eventually prevented in the future.
|
||||
|
||||
The reason is that it causes re-entrance into ``UnitOfWork::commit()`` while a commit
|
||||
is currently being processed. The ``UnitOfWork`` was never designed to support this,
|
||||
and its behavior in this situation is not covered by any tests.
|
||||
|
||||
This may lead to entity or collection updates being missed, applied only in parts and
|
||||
changes being lost at the end of the commit phase.
|
||||
|
||||
Naming convention
|
||||
~~~~~~~~~~~~~~~~~
|
||||
@@ -214,7 +227,11 @@ specific to a particular entity class's lifecycle.
|
||||
|
||||
<?php
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\PrePersistEventArgs;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
|
||||
use Doctrine\ORM\Mapping\PrePersist;
|
||||
use Doctrine\ORM\Mapping\PreUpdate;
|
||||
|
||||
#[Entity]
|
||||
#[HasLifecycleCallbacks]
|
||||
@@ -226,7 +243,7 @@ specific to a particular entity class's lifecycle.
|
||||
public $value;
|
||||
|
||||
#[PrePersist]
|
||||
public function doStuffOnPrePersist(LifecycleEventArgs $eventArgs)
|
||||
public function doStuffOnPrePersist(PrePersistEventArgs $eventArgs)
|
||||
{
|
||||
$this->createdAt = date('Y-m-d H:i:s');
|
||||
}
|
||||
@@ -246,7 +263,7 @@ specific to a particular entity class's lifecycle.
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\PrePersistEventArgs;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
@@ -260,7 +277,7 @@ specific to a particular entity class's lifecycle.
|
||||
public $value;
|
||||
|
||||
/** @PrePersist */
|
||||
public function doStuffOnPrePersist(LifecycleEventArgs $eventArgs)
|
||||
public function doStuffOnPrePersist(PrePersistEventArgs $eventArgs)
|
||||
{
|
||||
$this->createdAt = date('Y-m-d H:i:s');
|
||||
}
|
||||
@@ -281,10 +298,10 @@ specific to a particular entity class's lifecycle.
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="User">
|
||||
<!-- ... -->
|
||||
<lifecycle-callbacks>
|
||||
@@ -341,7 +358,7 @@ behaviors across different entity classes.
|
||||
|
||||
Note that they require much more detailed knowledge about the inner
|
||||
workings of the ``EntityManager`` and ``UnitOfWork`` classes. Please
|
||||
read the :ref:`Implementing Event Listeners<reference-events-implementing-listeners>` section
|
||||
read the :ref:`Implementing Event Listeners <reference-events-implementing-listeners>` section
|
||||
carefully if you are trying to write your own listener.
|
||||
|
||||
For event subscribers, there are no surprises. They declare the
|
||||
@@ -353,11 +370,11 @@ A lifecycle event listener looks like the following:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
class MyEventListener
|
||||
{
|
||||
public function preUpdate(LifecycleEventArgs $args)
|
||||
public function preUpdate(PreUpdateEventArgs $args)
|
||||
{
|
||||
$entity = $args->getObject();
|
||||
$entityManager = $args->getObjectManager();
|
||||
@@ -374,9 +391,9 @@ A lifecycle event subscriber may look like this:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\EventSubscriber;
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
|
||||
class MyEventSubscriber implements EventSubscriber
|
||||
{
|
||||
@@ -387,7 +404,7 @@ A lifecycle event subscriber may look like this:
|
||||
);
|
||||
}
|
||||
|
||||
public function postUpdate(LifecycleEventArgs $args)
|
||||
public function postUpdate(PostUpdateEventArgs $args)
|
||||
{
|
||||
$entity = $args->getObject();
|
||||
$entityManager = $args->getObjectManager();
|
||||
@@ -416,7 +433,7 @@ EventManager that is passed to the EntityManager factory:
|
||||
$eventManager->addEventListener([Events::preUpdate], new MyEventListener());
|
||||
$eventManager->addEventSubscriber(new MyEventSubscriber());
|
||||
|
||||
$entityManager = EntityManager::create($dbOpts, $config, $eventManager);
|
||||
$entityManager = new EntityManager($connection, $config, $eventManager);
|
||||
|
||||
You can also retrieve the event manager instance after the
|
||||
EntityManager was created:
|
||||
@@ -453,15 +470,14 @@ prePersist
|
||||
|
||||
There are two ways for the ``prePersist`` event to be triggered:
|
||||
|
||||
- One is obviously when you call ``EntityManager::persist()``. The
|
||||
event is also called for all :ref:`cascaded associations<transitive-persistence>`.
|
||||
- The other is inside the
|
||||
``flush()`` method when changes to associations are computed and
|
||||
this association is marked as :ref:`cascade: persist<transitive-persistence>`. Any new entity found
|
||||
during this operation is also persisted and ``prePersist`` called
|
||||
on it. This is called :ref:`persistence by reachability<persistence-by-reachability>`.
|
||||
- One is when you call ``EntityManager::persist()``. The
|
||||
event is also called for all :ref:`cascaded associations <transitive-persistence>`.
|
||||
- The other is inside the ``flush()`` method when changes to associations are computed and
|
||||
this association is marked as :ref:`cascade: persist <transitive-persistence>`. Any new entity found
|
||||
during this operation is also persisted and ``prePersist`` called
|
||||
on it. This is called :ref:`persistence by reachability <persistence-by-reachability>`.
|
||||
|
||||
In both cases you get passed a ``LifecycleEventArgs`` instance
|
||||
In both cases you get passed a ``PrePersistEventArgs`` instance
|
||||
which has access to the entity and the entity manager.
|
||||
|
||||
This event is only triggered on *initial* persist of an entity
|
||||
@@ -483,7 +499,7 @@ preRemove
|
||||
|
||||
The ``preRemove`` event is called on every entity immediately when it is passed
|
||||
to the ``EntityManager::remove()`` method. It is cascaded for all
|
||||
associations that are marked as :ref:`cascade: remove<transitive-persistence>`
|
||||
associations that are marked as :ref:`cascade: remove <transitive-persistence>`
|
||||
|
||||
It is not called for a DQL ``DELETE`` statement.
|
||||
|
||||
@@ -531,7 +547,7 @@ entities and their associations have been computed. This means, the
|
||||
- Collections scheduled for removal
|
||||
|
||||
To make use of the ``onFlush`` event you have to be familiar with the
|
||||
internal :ref:`UnitOfWork<unit-of-work>` API, which grants you access to the previously
|
||||
internal :ref:`UnitOfWork <unit-of-work>` API, which grants you access to the previously
|
||||
mentioned sets. See this example:
|
||||
|
||||
.. code-block:: php
|
||||
@@ -696,22 +712,33 @@ Restrictions for this event:
|
||||
postUpdate, postRemove, postPersist
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
These three post* events are called inside ``EntityManager::flush()``.
|
||||
These three ``post*`` events are called inside ``EntityManager::flush()``.
|
||||
Changes in here are not relevant to the persistence in the
|
||||
database, but you can use these events to alter non-persistable items,
|
||||
like non-mapped fields, logging or even associated classes that are
|
||||
not directly mapped by Doctrine.
|
||||
|
||||
- The ``postUpdate`` event occurs after the database
|
||||
update operations to entity data. It is not called for a DQL
|
||||
``UPDATE`` statement.
|
||||
- The ``postPersist`` event occurs for an entity after
|
||||
the entity has been made persistent. It will be invoked after the
|
||||
database insert operations. Generated primary key values are
|
||||
available in the postPersist event.
|
||||
update operations to entity data, but before the database transaction
|
||||
has been committed. It is not called for a DQL ``UPDATE`` statement.
|
||||
- The ``postPersist`` event occurs for an entity after the entity has
|
||||
been made persistent. It will be invoked after all database insert
|
||||
operations for new entities have been performed, but before the database
|
||||
transaction has been committed. Generated primary key values will be
|
||||
available for all entities at the time this event is triggered.
|
||||
- The ``postRemove`` event occurs for an entity after the
|
||||
entity has been deleted. It will be invoked after the database
|
||||
delete operations. It is not called for a DQL ``DELETE`` statement.
|
||||
entity has been deleted. It will be invoked after all database
|
||||
delete operations for entity rows have been executed, but before the
|
||||
database transaction has been committed. This event is not called for
|
||||
a DQL ``DELETE`` statement.
|
||||
|
||||
.. note::
|
||||
|
||||
At the time ``postPersist`` is called, there may still be collection and/or
|
||||
"extra" updates pending. The database may not yet be completely in
|
||||
sync with the entity states in memory, not even for the new entities. Similarly,
|
||||
also at the time ``postUpdate`` and ``postRemove`` are called, in-memory collections
|
||||
may still be in a "dirty" state or still contain removed entities.
|
||||
|
||||
.. warning::
|
||||
|
||||
@@ -830,69 +857,79 @@ you need to map the listener method using the event type mapping:
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
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\Persistence\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\PrePersistEventArgs;
|
||||
use Doctrine\ORM\Event\PreRemoveEventArgs;
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
class UserListener
|
||||
{
|
||||
#[PrePersist]
|
||||
public function prePersistHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function prePersistHandler(User $user, PrePersistEventArgs $event): void { // ... }
|
||||
|
||||
#[PostPersist]
|
||||
public function postPersistHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function postPersistHandler(User $user, PostPersistEventArgs $event): void { // ... }
|
||||
|
||||
#[PreUpdate]
|
||||
public function preUpdateHandler(User $user, PreUpdateEventArgs $event): void { // ... }
|
||||
|
||||
#[PostUpdate]
|
||||
public function postUpdateHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function postUpdateHandler(User $user, PostUpdateEventArgs $event): void { // ... }
|
||||
|
||||
#[PostRemove]
|
||||
public function postRemoveHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function postRemoveHandler(User $user, PostRemoveEventArgs $event): void { // ... }
|
||||
|
||||
#[PreRemove]
|
||||
public function preRemoveHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function preRemoveHandler(User $user, PreRemoveEventArgs $event): void { // ... }
|
||||
|
||||
#[PreFlush]
|
||||
public function preFlushHandler(User $user, PreFlushEventArgs $event): void { // ... }
|
||||
|
||||
#[PostLoad]
|
||||
public function postLoadHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function postLoadHandler(User $user, PostLoadEventArgs $event): void { // ... }
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
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\Persistence\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\PrePersistEventArgs;
|
||||
use Doctrine\ORM\Event\PreRemoveEventArgs;
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
class UserListener
|
||||
{
|
||||
/** @PrePersist */
|
||||
public function prePersistHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function prePersistHandler(User $user, PrePersistEventArgs $event): void { // ... }
|
||||
|
||||
/** @PostPersist */
|
||||
public function postPersistHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function postPersistHandler(User $user, PostPersistEventArgs $event): void { // ... }
|
||||
|
||||
/** @PreUpdate */
|
||||
public function preUpdateHandler(User $user, PreUpdateEventArgs $event): void { // ... }
|
||||
|
||||
/** @PostUpdate */
|
||||
public function postUpdateHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function postUpdateHandler(User $user, PostUpdateEventArgs $event): void { // ... }
|
||||
|
||||
/** @PostRemove */
|
||||
public function postRemoveHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function postRemoveHandler(User $user, PostRemoveEventArgs $event): void { // ... }
|
||||
|
||||
/** @PreRemove */
|
||||
public function preRemoveHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function preRemoveHandler(User $user, PreRemoveEventArgs $event): void { // ... }
|
||||
|
||||
/** @PreFlush */
|
||||
public function preFlushHandler(User $user, PreFlushEventArgs $event): void { // ... }
|
||||
|
||||
/** @PostLoad */
|
||||
public function postLoadHandler(User $user, LifecycleEventArgs $event): void { // ... }
|
||||
public function postLoadHandler(User $user, PostLoadEventArgs $event): void { // ... }
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
@@ -1006,7 +1043,7 @@ Implementing your own resolver:
|
||||
|
||||
// Configure the listener resolver only before instantiating the EntityManager
|
||||
$configurations->setEntityListenerResolver(new MyEntityListenerResolver);
|
||||
EntityManager::create(.., $configurations, ..);
|
||||
$entityManager = new EntityManager(.., $configurations, ..);
|
||||
|
||||
.. _reference-events-load-class-metadata:
|
||||
|
||||
@@ -1106,11 +1143,16 @@ and the EntityManager.
|
||||
}
|
||||
}
|
||||
|
||||
.. _LifecycleEventArgs: https://github.com/doctrine/orm/blob/HEAD/lib/Doctrine/ORM/Event/LifecycleEventArgs.php
|
||||
.. _PreUpdateEventArgs: https://github.com/doctrine/orm/blob/HEAD/lib/Doctrine/ORM/Event/PreUpdateEventArgs.php
|
||||
.. _PreFlushEventArgs: https://github.com/doctrine/orm/blob/HEAD/lib/Doctrine/ORM/Event/PreFlushEventArgs.php
|
||||
.. _PostFlushEventArgs: https://github.com/doctrine/orm/blob/HEAD/lib/Doctrine/ORM/Event/PostFlushEventArgs.php
|
||||
.. _OnFlushEventArgs: https://github.com/doctrine/orm/blob/HEAD/lib/Doctrine/ORM/Event/OnFlushEventArgs.php
|
||||
.. _OnClearEventArgs: https://github.com/doctrine/orm/blob/HEAD/lib/Doctrine/ORM/Event/OnClearEventArgs.php
|
||||
.. _LoadClassMetadataEventArgs: https://github.com/doctrine/orm/blob/HEAD/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php
|
||||
.. _OnClassMetadataNotFoundEventArgs: https://github.com/doctrine/orm/blob/HEAD/lib/Doctrine/ORM/Event/OnClassMetadataNotFoundEventArgs.php
|
||||
.. _PrePersistEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/PrePersistEventArgs.php
|
||||
.. _PreRemoveEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/PreRemoveEventArgs.php
|
||||
.. _PreUpdateEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/PreUpdateEventArgs.php
|
||||
.. _PostPersistEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/PostPersistEventArgs.php
|
||||
.. _PostRemoveEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/PostRemoveEventArgs.php
|
||||
.. _PostUpdateEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/PostUpdateEventArgs.php
|
||||
.. _PostLoadEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/PostLoadEventArgs.php
|
||||
.. _PreFlushEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/PreFlushEventArgs.php
|
||||
.. _PostFlushEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/PostFlushEventArgs.php
|
||||
.. _OnFlushEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/OnFlushEventArgs.php
|
||||
.. _OnClearEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/OnClearEventArgs.php
|
||||
.. _LoadClassMetadataEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/LoadClassMetadataEventArgs.php
|
||||
.. _OnClassMetadataNotFoundEventArgs: https://github.com/doctrine/orm/blob/HEAD/src/Event/OnClassMetadataNotFoundEventArgs.php
|
||||
|
||||
@@ -13,11 +13,10 @@ Database Schema
|
||||
How do I set the charset and collation for MySQL tables?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can't set these values with attributes, annotations or inside yml or
|
||||
xml mapping files. To make a database work with the default charset and
|
||||
collation you should configure MySQL to use it as default charset, or
|
||||
create the database with charset and collation details. This way they
|
||||
get inherited to all newly created database tables and columns.
|
||||
In your mapping configuration, the column definition (for example, the
|
||||
``#[Column]`` attribute) has an ``options`` parameter where you can specify
|
||||
the ``charset`` and ``collation``. The default values are ``utf8`` and
|
||||
``utf8_unicode_ci``, respectively.
|
||||
|
||||
Entity Classes
|
||||
--------------
|
||||
@@ -38,7 +37,7 @@ upon insert:
|
||||
|
||||
private string $algorithm = "sha1";
|
||||
/** @var self::STATUS_* */
|
||||
private int $status = self:STATUS_DISABLED;
|
||||
private int $status = self::STATUS_DISABLED;
|
||||
}
|
||||
|
||||
.
|
||||
@@ -102,7 +101,7 @@ The many-to-many association is only supporting foreign keys in the table defini
|
||||
To work with many-to-many tables containing extra columns you have to use the
|
||||
foreign keys as primary keys feature of Doctrine ORM.
|
||||
|
||||
See :doc:`the tutorial on composite primary keys for more information<../tutorials/composite-primary-keys>`.
|
||||
See :doc:`the tutorial on composite primary keys for more information <../tutorials/composite-primary-keys>`.
|
||||
|
||||
|
||||
How can i paginate fetch-joined collections?
|
||||
|
||||
@@ -28,10 +28,11 @@ table alias of the SQL table of the entity.
|
||||
In the case of joined or single table inheritance, you always get passed the ClassMetadata of the
|
||||
inheritance root. This is necessary to avoid edge cases that would break the SQL when applying the filters.
|
||||
|
||||
Parameters for the query should be set on the filter object by
|
||||
``SQLFilter#setParameter()``. Only parameters set via this function can be used
|
||||
in filters. The ``SQLFilter#getParameter()`` function takes care of the
|
||||
proper quoting of parameters.
|
||||
For the filter to correctly function, the following rules must be followed. Failure to do so will lead to unexpected results from the query cache.
|
||||
1. Parameters for the query should be set on the filter object by ``SQLFilter#setParameter()`` before the filter is used by the ORM ( i.e. do not set parameters inside ``SQLFilter#addFilterConstraint()`` function ).
|
||||
2. The filter must be deterministic. Don't change the values base on external inputs.
|
||||
|
||||
The ``SQLFilter#getParameter()`` function takes care of the proper quoting of parameters.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -92,3 +93,34 @@ object.
|
||||
want to refresh or reload an object after having modified a filter or the
|
||||
FilterCollection, then you should clear the EntityManager and re-fetch your
|
||||
entities, having the new rules for filtering applied.
|
||||
|
||||
|
||||
Suspending/Restoring Filters
|
||||
----------------------------
|
||||
When a filter is disabled, the instance is fully deleted and all the filter
|
||||
parameters previously set are lost. Then, if you enable it again, a new filter
|
||||
is created without the previous filter parameters. If you want to keep a filter
|
||||
(in order to use it later) but temporary disable it, you'll need to use the
|
||||
``FilterCollection#suspend($name)`` and ``FilterCollection#restore($name)``
|
||||
methods instead.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$filter = $em->getFilters()->enable("locale");
|
||||
$filter->setParameter('locale', 'en');
|
||||
|
||||
// Temporary suspend the filter
|
||||
$filter = $em->getFilters()->suspend("locale");
|
||||
|
||||
// Do things
|
||||
|
||||
// Then restore it, the locale parameter will still be set
|
||||
$filter = $em->getFilters()->restore("locale");
|
||||
|
||||
.. warning::
|
||||
If you enable a previously disabled filter, doctrine will create a new
|
||||
one without keeping any of the previously parameter set with
|
||||
``SQLFilter#setParameter()`` or ``SQLFilter#getParameterList()``. If you
|
||||
want to restore the previously disabled filter instead, you must use the
|
||||
``FilterCollection#restore($name)`` method.
|
||||
|
||||
@@ -45,8 +45,7 @@ in scenarios where data is loaded for read-only purposes.
|
||||
Read-Only Entities
|
||||
------------------
|
||||
|
||||
You can mark entities as read only (See metadata mapping
|
||||
references for details).
|
||||
You can mark entities as read only. For details, see :ref:`attrref_entity`
|
||||
|
||||
This means that the entity marked as read only is never considered for updates.
|
||||
During flush on the EntityManager these entities are skipped even if properties
|
||||
@@ -55,8 +54,6 @@ changed.
|
||||
Read-Only allows to persist new entities of a kind and remove existing ones,
|
||||
they are just not considered for updates.
|
||||
|
||||
See :ref:`annref_entity`
|
||||
|
||||
You can also explicitly mark individual entities read only directly on the
|
||||
UnitOfWork via a call to ``markReadOnly()``:
|
||||
|
||||
@@ -94,7 +91,7 @@ Apply Best Practices
|
||||
A lot of the points mentioned in the Best Practices chapter will
|
||||
also positively affect the performance of Doctrine.
|
||||
|
||||
See :doc:`Best Practices <reference/best-practices>`
|
||||
See :doc:`Best Practices </reference/best-practices>`
|
||||
|
||||
Change Tracking policies
|
||||
------------------------
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
Inheritance Mapping
|
||||
===================
|
||||
|
||||
This chapter explains the available options for mapping class
|
||||
hierarchies.
|
||||
|
||||
Mapped Superclasses
|
||||
-------------------
|
||||
|
||||
@@ -12,19 +15,52 @@ is common to multiple entity classes.
|
||||
|
||||
Mapped superclasses, just as regular, non-mapped classes, can
|
||||
appear in the middle of an otherwise mapped inheritance hierarchy
|
||||
(through Single Table Inheritance or Class Table Inheritance).
|
||||
(through Single Table Inheritance or Class Table Inheritance). They
|
||||
are not query-able, and need not have an ``#[Id]`` property.
|
||||
|
||||
No database table will be created for a mapped superclass itself,
|
||||
only for entity classes inheriting from it. That implies that a
|
||||
mapped superclass cannot be the ``targetEntity`` in associations.
|
||||
|
||||
In other words, a mapped superclass can use unidirectional One-To-One
|
||||
and Many-To-One associations where it is the owning side.
|
||||
Many-To-Many associations are only possible if the mapped
|
||||
superclass is only used in exactly one entity at the moment. For further
|
||||
support of inheritance, the single or joined table inheritance features
|
||||
have to be used.
|
||||
|
||||
.. note::
|
||||
|
||||
A mapped superclass cannot be an entity, it is not query-able and
|
||||
persistent relationships defined by a mapped superclass must be
|
||||
unidirectional (with an owning side only). This means that One-To-Many
|
||||
associations are not possible on a mapped superclass at all.
|
||||
Furthermore Many-To-Many associations are only possible if the
|
||||
mapped superclass is only used in exactly one entity at the moment.
|
||||
For further support of inheritance, the single or
|
||||
joined table inheritance features have to be used.
|
||||
One-To-Many associations are not generally possible on a mapped
|
||||
superclass, since they require the "many" side to hold the foreign
|
||||
key.
|
||||
|
||||
It is, however, possible to use the :doc:`ResolveTargetEntityListener </cookbook/resolve-target-entity-listener>`
|
||||
to replace references to a mapped superclass with an entity class at runtime.
|
||||
As long as there is only one entity subclass inheriting from the mapped
|
||||
superclass and all references to the mapped superclass are resolved to that
|
||||
entity class at runtime, the mapped superclass *can* use One-To-Many associations
|
||||
and be named as the ``targetEntity`` on the owning sides.
|
||||
|
||||
.. warning::
|
||||
|
||||
At least when using attributes or annotations to specify your mapping,
|
||||
it *seems* as if you could inherit from a base class that is neither
|
||||
an entity nor a mapped superclass, but has properties with mapping configuration
|
||||
on them that would also be used in the inheriting class.
|
||||
|
||||
This, however, is due to how the corresponding mapping
|
||||
drivers work and what the PHP reflection API reports for inherited fields.
|
||||
|
||||
Such a configuration is explicitly not supported. To give just one example,
|
||||
it will break for ``private`` properties.
|
||||
|
||||
.. note::
|
||||
|
||||
You may be tempted to use traits to mix mapped fields or relationships
|
||||
into your entity classes to circumvent some of the limitations of
|
||||
mapped superclasses. Before doing that, please read the section on traits
|
||||
in the :doc:`Limitations and Known Issues </reference/limitations-and-known-issues>` chapter.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -77,21 +113,76 @@ like this (this is for SQLite):
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
CREATE TABLE EntitySubClass (mapped1 INTEGER NOT NULL, mapped2 TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, related1_id INTEGER DEFAULT NULL, PRIMARY KEY(id))
|
||||
CREATE TABLE Employee (mapped1 INTEGER NOT NULL, mapped2 TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, toothbrush_id INTEGER DEFAULT NULL, PRIMARY KEY(id))
|
||||
|
||||
As you can see from this DDL snippet, there is only a single table
|
||||
for the entity subclass. All the mappings from the mapped
|
||||
superclass were inherited to the subclass as if they had been
|
||||
defined on that class directly.
|
||||
|
||||
Entity Inheritance
|
||||
------------------
|
||||
|
||||
As soon as one entity class inherits from another entity class, either
|
||||
directly, with a mapped superclass or other unmapped (also called
|
||||
"transient") classes in between, these entities form an inheritance
|
||||
hierarchy. The topmost entity class in this hierarchy is called the
|
||||
root entity, and the hierarchy includes all entities that are
|
||||
descendants of this root entity.
|
||||
|
||||
On the root entity class, ``#[InheritanceType]``,
|
||||
``#[DiscriminatorColumn]`` and ``#[DiscriminatorMap]`` must be specified.
|
||||
|
||||
``#[InheritanceType]`` specifies one of the two available inheritance
|
||||
mapping strategies that are explained in the following sections.
|
||||
|
||||
``#[DiscriminatorColumn]`` designates the so-called discriminator column.
|
||||
This is an extra column in the table that keeps information about which
|
||||
type from the hierarchy applies for a particular database row.
|
||||
|
||||
``#[DiscriminatorMap]`` declares the possible values for the discriminator
|
||||
column and maps them to class names in the hierarchy. This discriminator map
|
||||
has to declare all non-abstract entity classes that exist in that particular
|
||||
inheritance hierarchy. That includes the root as well as any intermediate
|
||||
entity classes, given they are not abstract.
|
||||
|
||||
The names of the classes in the discriminator map do not need to be fully
|
||||
qualified if the classes are contained in the same namespace as the entity
|
||||
class on which the discriminator map is applied.
|
||||
|
||||
If no discriminator map is provided, then the map is generated
|
||||
automatically. The automatically generated discriminator map contains the
|
||||
lowercase short name of each class as key.
|
||||
|
||||
.. note::
|
||||
|
||||
Automatically generating the discriminator map is very expensive
|
||||
computation-wise. The mapping driver has to provide all classes
|
||||
for which mapping configuration exists, and those have to be
|
||||
loaded and checked against the current inheritance hierarchy
|
||||
to see if they are part of it. The resulting map, however, can be kept
|
||||
in the metadata cache.
|
||||
|
||||
Performance impact on to-one associations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There is a general performance consideration when using entity inheritance:
|
||||
If the target-entity of a many-to-one or one-to-one association is part of
|
||||
an inheritance hierarchy, it is preferable for performance reasons that it
|
||||
be a leaf entity (ie. have no subclasses).
|
||||
|
||||
Otherwise, the ORM is currently unable to tell beforehand which entity class
|
||||
will have to be used, and so no appropriate proxy instance can be created.
|
||||
That means the referred-to entities will *always* be loaded eagerly, which
|
||||
might even propagate to relationships of these entities (in the case of
|
||||
self-referencing associations).
|
||||
|
||||
Single Table Inheritance
|
||||
------------------------
|
||||
|
||||
`Single Table Inheritance <https://martinfowler.com/eaaCatalog/singleTableInheritance.html>`_
|
||||
is an inheritance mapping strategy where all classes of a hierarchy
|
||||
are mapped to a single database table. In order to distinguish
|
||||
which row represents which type in the hierarchy a so-called
|
||||
discriminator column is used.
|
||||
is an inheritance mapping strategy where all classes of a hierarchy are
|
||||
mapped to a single database table.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -156,27 +247,9 @@ Example:
|
||||
MyProject\Model\Employee:
|
||||
type: entity
|
||||
|
||||
Things to note:
|
||||
|
||||
|
||||
- The ``#[InheritanceType]`` and ``#[DiscriminatorColumn]`` must be
|
||||
specified on the topmost class that is part of the mapped entity
|
||||
hierarchy.
|
||||
- The ``#[DiscriminatorMap]`` specifies which values of the
|
||||
discriminator column identify a row as being of a certain type. In
|
||||
the case above a value of "person" identifies a row as being of
|
||||
type ``Person`` and "employee" identifies a row as being of type
|
||||
``Employee``.
|
||||
- All entity classes that is part of the mapped entity hierarchy
|
||||
(including the topmost class) should be specified in the
|
||||
``#[DiscriminatorMap]``. In the case above Person class included.
|
||||
- The names of the classes in the discriminator map do not need to
|
||||
be fully qualified if the classes are contained in the same
|
||||
namespace as the entity class on which the discriminator map is
|
||||
applied.
|
||||
- If no discriminator map is provided, then the map is generated
|
||||
automatically. The automatically generated discriminator map
|
||||
contains the lowercase short name of each class as key.
|
||||
In this example, the ``#[DiscriminatorMap]`` specifies that in the
|
||||
discriminator column, a value of "person" identifies a row as being of type
|
||||
``Person`` and employee" identifies a row as being of type ``Employee``.
|
||||
|
||||
Design-time considerations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -192,17 +265,10 @@ Performance impact
|
||||
|
||||
This strategy is very efficient for querying across all types in
|
||||
the hierarchy or for specific types. No table joins are required,
|
||||
only a WHERE clause listing the type identifiers. In particular,
|
||||
only a ``WHERE`` clause listing the type identifiers. In particular,
|
||||
relationships involving types that employ this mapping strategy are
|
||||
very performing.
|
||||
|
||||
There is a general performance consideration with Single Table
|
||||
Inheritance: If the target-entity of a many-to-one or one-to-one
|
||||
association is an STI entity, it is preferable for performance reasons that it
|
||||
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
|
||||
Otherwise Doctrine *CANNOT* create proxy instances
|
||||
of this entity and will *ALWAYS* load the entity eagerly.
|
||||
|
||||
SQL Schema considerations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -210,7 +276,7 @@ For Single-Table-Inheritance to work in scenarios where you are
|
||||
using either a legacy database schema or a self-written database
|
||||
schema you have to make sure that all columns that are not in the
|
||||
root entity but in any of the different sub-entities has to allow
|
||||
null values. Columns that have NOT NULL constraints have to be on
|
||||
null values. Columns that have ``NOT NULL`` constraints have to be on
|
||||
the root entity of the single-table inheritance hierarchy.
|
||||
|
||||
Class Table Inheritance
|
||||
@@ -220,10 +286,11 @@ Class Table Inheritance
|
||||
is an inheritance mapping strategy where each class in a hierarchy
|
||||
is mapped to several tables: its own table and the tables of all
|
||||
parent classes. The table of a child class is linked to the table
|
||||
of a parent class through a foreign key constraint. Doctrine ORM
|
||||
implements this strategy through the use of a discriminator column
|
||||
in the topmost table of the hierarchy because this is the easiest
|
||||
way to achieve polymorphic queries with Class Table Inheritance.
|
||||
of a parent class through a foreign key constraint.
|
||||
|
||||
The discriminator column is placed in the topmost table of the hierarchy,
|
||||
because this is the easiest way to achieve polymorphic queries with Class
|
||||
Table Inheritance.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -247,24 +314,9 @@ Example:
|
||||
// ...
|
||||
}
|
||||
|
||||
Things to note:
|
||||
|
||||
|
||||
- The ``#[InheritanceType]``, ``#[DiscriminatorColumn]`` and
|
||||
``#[DiscriminatorMap]`` must be specified on the topmost class that is
|
||||
part of the mapped entity hierarchy.
|
||||
- The ``#[DiscriminatorMap]`` specifies which values of the
|
||||
discriminator column identify a row as being of which type. In the
|
||||
case above a value of "person" identifies a row as being of type
|
||||
``Person`` and "employee" identifies a row as being of type
|
||||
``Employee``.
|
||||
- The names of the classes in the discriminator map do not need to
|
||||
be fully qualified if the classes are contained in the same
|
||||
namespace as the entity class on which the discriminator map is
|
||||
applied.
|
||||
- If no discriminator map is provided, then the map is generated
|
||||
automatically. The automatically generated discriminator map
|
||||
contains the lowercase short name of each class as key.
|
||||
As before, the ``#[DiscriminatorMap]`` specifies that in the
|
||||
discriminator column, a value of "person" identifies a row as being of type
|
||||
``Person`` and "employee" identifies a row as being of type ``Employee``.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -295,20 +347,13 @@ perform just about any query which can have a negative impact on
|
||||
performance, especially with large tables and/or large hierarchies.
|
||||
When partial objects are allowed, either globally or on the
|
||||
specific query, then querying for any type will not cause the
|
||||
tables of subtypes to be OUTER JOINed which can increase
|
||||
tables of subtypes to be ``OUTER JOIN``ed which can increase
|
||||
performance but the resulting partial objects will not fully load
|
||||
themselves on access of any subtype fields, so accessing fields of
|
||||
subtypes after such a query is not safe.
|
||||
|
||||
There is a general performance consideration with Class Table
|
||||
Inheritance: If the target-entity of a many-to-one or one-to-one
|
||||
association is a CTI entity, it is preferable for performance reasons that it
|
||||
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
|
||||
Otherwise Doctrine *CANNOT* create proxy instances
|
||||
of this entity and will *ALWAYS* load the entity eagerly.
|
||||
|
||||
There is also another important performance consideration that it is *NOT POSSIBLE*
|
||||
to query for the base entity without any LEFT JOINs to the sub-types.
|
||||
There is also another important performance consideration that it is *not possible*
|
||||
to query for the base entity without any ``LEFT JOIN``s to the sub-types.
|
||||
|
||||
SQL Schema considerations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -326,14 +371,16 @@ column and cascading on delete.
|
||||
Overrides
|
||||
---------
|
||||
|
||||
Used to override a mapping for an entity field or relationship. Can only be
|
||||
applied to an entity that extends a mapped superclass or uses a trait to
|
||||
override a relationship or field mapping defined by the mapped superclass or
|
||||
trait.
|
||||
Overrides can only be applied to entities that extend a mapped superclass or
|
||||
use traits. They are used to override a mapping for an entity field or
|
||||
relationship defined in that mapped superclass or trait.
|
||||
|
||||
It is not possible to override attributes or associations in entity to entity
|
||||
inheritance scenarios, because this can cause unforseen edge case behavior and
|
||||
increases complexity in ORM internal classes.
|
||||
It is not supported to use overrides in entity inheritance scenarios.
|
||||
|
||||
.. note::
|
||||
|
||||
When using traits, make sure not to miss the warnings given in the
|
||||
:doc:`Limitations and Known Issues </reference/limitations-and-known-issues>` chapter.
|
||||
|
||||
|
||||
Association Override
|
||||
@@ -538,10 +585,11 @@ Example:
|
||||
|
||||
Things to note:
|
||||
|
||||
- The "association override" specifies the overrides base on the property name.
|
||||
- This feature is available for all kind of associations. (OneToOne, OneToMany, ManyToOne, ManyToMany)
|
||||
- The association type *CANNOT* be changed.
|
||||
- The override could redefine the joinTables or joinColumns depending on the association type.
|
||||
- The "association override" specifies the overrides based on the property
|
||||
name.
|
||||
- This feature is available for all kind of associations (OneToOne, OneToMany, ManyToOne, ManyToMany).
|
||||
- The association type *cannot* be changed.
|
||||
- The override could redefine the ``joinTables`` or ``joinColumns`` depending on the association type.
|
||||
- The override could redefine ``inversedBy`` to reference more than one extended entity.
|
||||
- The override could redefine fetch to modify the fetch strategy of the extended entity.
|
||||
|
||||
@@ -714,8 +762,8 @@ Could be used by an entity that extends a mapped superclass to override a field
|
||||
|
||||
Things to note:
|
||||
|
||||
- The "attribute override" specifies the overrides base on the property name.
|
||||
- The column type *CANNOT* be changed. If the column type is not equal you get a ``MappingException``
|
||||
- The "attribute override" specifies the overrides based on the property name.
|
||||
- The column type *cannot* be changed. If the column type is not equal, you get a ``MappingException``.
|
||||
- The override can redefine all the attributes except the type.
|
||||
|
||||
Query the Type
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
:orphan:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
The installation chapter has moved to :doc:`Installation and Configuration <reference/configuration>`_.
|
||||
The installation chapter has moved to :doc:`Installation and Configuration </reference/configuration>`.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
Limitations and Known Issues
|
||||
============================
|
||||
|
||||
We try to make using Doctrine2 a very pleasant experience.
|
||||
We try to make using Doctrine ORM a very pleasant experience.
|
||||
Therefore we think it is very important to be honest about the
|
||||
current limitations to our users. Much like every other piece of
|
||||
software Doctrine2 is not perfect and far from feature complete.
|
||||
software the ORM is not perfect and far from feature complete.
|
||||
This section should give you an overview of current limitations of
|
||||
Doctrine ORM as well as critical known issues that you should know
|
||||
about.
|
||||
@@ -130,10 +130,63 @@ included in the core of Doctrine ORM. However there are already two
|
||||
extensions out there that offer support for Nested Set with
|
||||
ORM:
|
||||
|
||||
|
||||
- `Doctrine2 Hierarchical-Structural Behavior <https://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior>`_
|
||||
- `Doctrine2 NestedSet <https://github.com/blt04/doctrine2-nestedset>`_
|
||||
|
||||
Using Traits in Entity Classes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The use of traits in entity or mapped superclasses, at least when they
|
||||
include mapping configuration or mapped fields, is currently not
|
||||
endorsed by the Doctrine project. The reasons for this are as follows.
|
||||
|
||||
Traits were added in PHP 5.4 more than 10 years ago, but at the same time
|
||||
more than two years after the initial Doctrine 2 release and the time where
|
||||
core components were designed.
|
||||
|
||||
In fact, this documentation mentions traits only in the context of
|
||||
:doc:`overriding field association mappings in subclasses </tutorials/override-field-association-mappings-in-subclasses>`.
|
||||
Coverage of traits in test cases is practically nonexistent.
|
||||
|
||||
Thus, you should at least be aware that when using traits in your entity and
|
||||
mapped superclasses, you will be in uncharted terrain.
|
||||
|
||||
.. warning::
|
||||
|
||||
There be dragons.
|
||||
|
||||
From a more technical point of view, traits basically work at the language level
|
||||
as if the code contained in them had been copied into the class where the trait
|
||||
is used, and even private fields are accessible by the using class. In addition to
|
||||
that, some precedence and conflict resolution rules apply.
|
||||
|
||||
When it comes to loading mapping configuration, the annotation and attribute drivers
|
||||
rely on PHP reflection to inspect class properties including their docblocks.
|
||||
As long as the results are consistent with what a solution *without* traits would
|
||||
have produced, this is probably fine.
|
||||
|
||||
However, to mention known limitations, it is currently not possible to use "class"
|
||||
level `annotations <https://github.com/doctrine/orm/pull/1517>`_ or
|
||||
`attributes <https://github.com/doctrine/orm/issues/8868>`_ on traits, and attempts to
|
||||
improve parser support for traits as `here <https://github.com/doctrine/annotations/pull/102>`_
|
||||
or `there <https://github.com/doctrine/annotations/pull/63>`_ have been abandoned
|
||||
due to complexity.
|
||||
|
||||
XML mapping configuration probably needs to completely re-configure or otherwise
|
||||
copy-and-paste configuration for fields used from traits.
|
||||
|
||||
Mapping multiple private fields of the same name
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When two classes, say a mapped superclass and an entity inheriting from it,
|
||||
both contain a ``private`` field of the same name, this will lead to a ``MappingException``.
|
||||
|
||||
Since the fields are ``private``, both are technically separate and can contain
|
||||
different values at the same time. However, the ``ClassMetadata`` configuration used
|
||||
internally by the ORM currently refers to fields by their name only, without taking the
|
||||
class containing the field into consideration. This makes it impossible to keep separate
|
||||
mapping configuration for both fields.
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
@@ -177,27 +230,3 @@ MySQL with MyISAM tables
|
||||
Doctrine cannot provide atomic operations when calling ``EntityManager#flush()`` if one
|
||||
of the tables involved uses the storage engine MyISAM. You must use InnoDB or
|
||||
other storage engines that support transactions if you need integrity.
|
||||
|
||||
Entities, Proxies and Reflection
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Using methods for Reflection on entities can be prone to error, when the entity
|
||||
is actually a proxy the following methods will not work correctly:
|
||||
|
||||
- ``new ReflectionClass``
|
||||
- ``new ReflectionObject``
|
||||
- ``get_class()``
|
||||
- ``get_parent_class()``
|
||||
|
||||
This is why ``Doctrine\Common\Util\ClassUtils`` class exists that has similar
|
||||
methods, which resolve the proxy problem beforehand.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
|
||||
$bookProxy = $entityManager->getReference('Acme\Book');
|
||||
|
||||
$reflection = ClassUtils::newReflectionClass($bookProxy);
|
||||
$class = ClassUtils::getClass($bookProxy)¸
|
||||
|
||||
@@ -13,11 +13,16 @@ metadata:
|
||||
|
||||
|
||||
- **XML files** (XmlDriver)
|
||||
- **Class DocBlock Annotations** (AnnotationDriver)
|
||||
- **Attributes** (AttributeDriver)
|
||||
- **YAML files** (YamlDriver)
|
||||
- **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``
|
||||
@@ -40,8 +45,9 @@ an entity.
|
||||
|
||||
|
||||
If you want to use one of the included core metadata drivers you need to
|
||||
configure it. If you pick the annotation driver, you will additionally
|
||||
need to install ``doctrine/annotations``. All the drivers are in the
|
||||
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:
|
||||
|
||||
.. code-block:: php
|
||||
@@ -75,8 +81,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
|
||||
*
|
||||
@@ -87,8 +93,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();
|
||||
|
||||
@@ -96,7 +101,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
|
||||
*/
|
||||
@@ -117,22 +122,22 @@ the ``FileDriver`` implementation for you to extend from:
|
||||
class MyMetadataDriver extends FileDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected $_fileExtension = '.dcm.ext';
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
$data = $this->_loadMappingFile($file);
|
||||
|
||||
|
||||
// populate ClassMetadata instance from $data
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function _loadMappingFile($file)
|
||||
{
|
||||
@@ -198,5 +203,3 @@ iterate over them:
|
||||
foreach ($class->fieldMappings as $fieldMapping) {
|
||||
echo $fieldMapping['fieldName'] . "\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -250,6 +250,40 @@ The first parameter is the name of the column in the SQL result set
|
||||
and the second parameter is the result alias under which the value
|
||||
of the column will be placed in the transformed Doctrine result.
|
||||
|
||||
Special case: DTOs
|
||||
...................
|
||||
|
||||
You can also use ``ResultSetMapping`` to map the results of a native SQL
|
||||
query to a DTO (Data Transfer Object). This is done by adding scalar
|
||||
results for each argument of the DTO's constructor, then filling the
|
||||
``newObjectMappings`` property of the ``ResultSetMapping`` with
|
||||
information about where to map each scalar result:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
$rsm = new ResultSetMapping();
|
||||
$rsm->addScalarResult('name', 1, 'string');
|
||||
$rsm->addScalarResult('email', 2, 'string');
|
||||
$rsm->addScalarResult('city', 3, 'string');
|
||||
$rsm->newObjectMappings['name'] = [
|
||||
'className' => CmsUserDTO::class,
|
||||
'objIndex' => 0, // a result can contain many DTOs, this is the index of the DTO to map to
|
||||
'argIndex' => 0, // each scalar result can be mapped to a different argument of the DTO constructor
|
||||
];
|
||||
$rsm->newObjectMappings['email'] = [
|
||||
'className' => CmsUserDTO::class,
|
||||
'objIndex' => 0,
|
||||
'argIndex' => 1,
|
||||
];
|
||||
$rsm->newObjectMappings['city'] = [
|
||||
'className' => CmsUserDTO::class,
|
||||
'objIndex' => 0,
|
||||
'argIndex' => 2,
|
||||
];
|
||||
|
||||
|
||||
Meta results
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Partial Objects
|
||||
|
||||
Creating Partial Objects through DQL is deprecated and
|
||||
will be removed in the future, use data transfer object
|
||||
support in DQL instead. (`Details
|
||||
support in DQL instead. (\ `Details
|
||||
<https://github.com/doctrine/orm/issues/8471>`_)
|
||||
|
||||
A partial object is an object whose state is not fully initialized
|
||||
|
||||
@@ -167,7 +167,7 @@ The API of the ClassMetadataBuilder has the following methods with a fluent inte
|
||||
- ``addNamedQuery($name, $dqlQuery)``
|
||||
- ``setJoinedTableInheritance()``
|
||||
- ``setSingleTableInheritance()``
|
||||
- ``setDiscriminatorColumn($name, $type = 'string', $length = 255)``
|
||||
- ``setDiscriminatorColumn($name, $type = 'string', $length = 255, $columnDefinition = null, $enumType = null, $options = [])``
|
||||
- ``addDiscriminatorMapClass($name, $class)``
|
||||
- ``setChangeTrackingPolicyDeferredExplicit()``
|
||||
- ``setChangeTrackingPolicyNotify()``
|
||||
|
||||
@@ -253,7 +253,7 @@ Calling ``setParameter()`` automatically infers which type you are setting as
|
||||
value. This works for integers, arrays of strings/integers, DateTime instances
|
||||
and for managed entities. If you want to set a type explicitly you can call
|
||||
the third argument to ``setParameter()`` explicitly. It accepts either a DBAL
|
||||
Doctrine\DBAL\ParameterType::* or a DBAL Type name for conversion.
|
||||
``Doctrine\DBAL\ParameterType::*`` or a DBAL Type name for conversion.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -578,8 +578,6 @@ of DQL. It takes 3 parameters: ``$dqlPartName``, ``$dqlPart`` and
|
||||
not (no effect on the ``where`` and ``having`` DQL query parts,
|
||||
which always override all previously defined items)
|
||||
|
||||
-
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
@@ -322,7 +322,10 @@ level cache region.
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="Country">
|
||||
<cache usage="READ_ONLY" region="my_entity_region" />
|
||||
<id name="id" type="integer" column="id">
|
||||
@@ -427,7 +430,10 @@ It caches the primary keys of association and cache each element will be cached
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="State">
|
||||
|
||||
<cache usage="NONSTRICT_READ_WRITE" />
|
||||
|
||||
@@ -12,9 +12,8 @@ page only handles Security issues in the ORM.
|
||||
|
||||
- `DBAL Security Page <https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/security.html>`
|
||||
|
||||
If you find a Security bug in Doctrine, please report it on Jira and change the
|
||||
Security Level to "Security Issues". It will be visible to Doctrine Core
|
||||
developers and you only.
|
||||
If you find a Security bug in Doctrine, please follow our
|
||||
`Security reporting guidelines <https://www.doctrine-project.org/policies/security.html#reporting>`_.
|
||||
|
||||
User input and Doctrine ORM
|
||||
---------------------------
|
||||
|
||||
@@ -88,7 +88,7 @@ requirement.
|
||||
|
||||
A more convenient alternative for explicit transaction demarcation is the use
|
||||
of provided control abstractions in the form of
|
||||
``Connection#transactional($func)`` and ``EntityManager#transactional($func)``.
|
||||
``Connection#transactional($func)`` and ``EntityManager#wrapInTransaction($func)``.
|
||||
When used, these control abstractions ensure that you never forget to rollback
|
||||
the transaction, in addition to the obvious code reduction. An example that is
|
||||
functionally equivalent to the previously shown code looks as follows:
|
||||
@@ -96,26 +96,28 @@ functionally equivalent to the previously shown code looks as follows:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// transactional with Connection instance
|
||||
// $conn instanceof Connection
|
||||
$conn->transactional(function($conn) {
|
||||
// ... do some work
|
||||
$user = new User;
|
||||
$user->setName('George');
|
||||
});
|
||||
|
||||
// transactional with EntityManager instance
|
||||
// $em instanceof EntityManager
|
||||
$em->transactional(function($em) {
|
||||
$em->wrapInTransaction(function($em) {
|
||||
// ... do some work
|
||||
$user = new User;
|
||||
$user->setName('George');
|
||||
$em->persist($user);
|
||||
});
|
||||
|
||||
.. warning::
|
||||
|
||||
For historical reasons, ``EntityManager#transactional($func)`` will return
|
||||
``true`` whenever the return value of ``$func`` is loosely false.
|
||||
Some examples of this include ``array()``, ``"0"``, ``""``, ``0``, and
|
||||
``null``.
|
||||
|
||||
The difference between ``Connection#transactional($func)`` and
|
||||
``EntityManager#transactional($func)`` is that the latter
|
||||
abstraction flushes the ``EntityManager`` prior to transaction
|
||||
commit and rolls back the transaction when an
|
||||
exception occurs.
|
||||
commit and in case of an exception the ``EntityManager`` gets closed
|
||||
in addition to the transaction rollback.
|
||||
|
||||
.. _transactions-and-concurrency_exception-handling:
|
||||
|
||||
@@ -412,7 +414,7 @@ Doctrine ORM currently supports two pessimistic lock modes:
|
||||
locks other concurrent requests that attempt to update or lock rows
|
||||
in write mode.
|
||||
|
||||
You can use pessimistic locks in three different scenarios:
|
||||
You can use pessimistic locks in four different scenarios:
|
||||
|
||||
|
||||
1. Using
|
||||
@@ -424,6 +426,10 @@ You can use pessimistic locks in three different scenarios:
|
||||
or
|
||||
``EntityManager#lock($entity, \Doctrine\DBAL\LockMode::PESSIMISTIC_READ)``
|
||||
3. Using
|
||||
``EntityManager#refresh($entity, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE)``
|
||||
or
|
||||
``EntityManager#refresh($entity, \Doctrine\DBAL\LockMode::PESSIMISTIC_READ)``
|
||||
4. Using
|
||||
``Query#setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE)``
|
||||
or
|
||||
``Query#setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_READ)``
|
||||
|
||||
179
docs/en/reference/typedfieldmapper.rst
Normal file
179
docs/en/reference/typedfieldmapper.rst
Normal file
@@ -0,0 +1,179 @@
|
||||
Implementing a TypedFieldMapper
|
||||
===============================
|
||||
|
||||
.. versionadded:: 2.14
|
||||
|
||||
You can specify custom typed field mapping between PHP type and DBAL type using ``Doctrine\ORM\Configuration``
|
||||
and a custom ``Doctrine\ORM\Mapping\TypedFieldMapper`` implementation.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$configuration->setTypedFieldMapper(new CustomTypedFieldMapper());
|
||||
|
||||
|
||||
DefaultTypedFieldMapper
|
||||
-----------------------
|
||||
|
||||
By default the ``Doctrine\ORM\Mapping\DefaultTypedFieldMapper`` is used, and you can pass an array of
|
||||
PHP type => DBAL type mappings into its constructor to override the default behavior or add new mappings.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use App\CustomIds\CustomIdObject;
|
||||
use App\DBAL\Type\CustomIdObjectType;
|
||||
use Doctrine\ORM\Mapping\DefaultTypedFieldMapper;
|
||||
|
||||
$configuration->setTypedFieldMapper(new DefaultTypedFieldMapper([
|
||||
CustomIdObject::class => CustomIdObjectType::class,
|
||||
]));
|
||||
|
||||
Then, an entity using the ``CustomIdObject`` typed field will be correctly assigned its DBAL type
|
||||
(``CustomIdObjectType``) without the need of explicit declaration.
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'cms_users_typed_with_custom_typed_field')]
|
||||
class UserTypedWithCustomTypedField
|
||||
{
|
||||
#[ORM\Column]
|
||||
public CustomIdObject $customId;
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
.. 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>
|
||||
<entity name="UserTypedWithCustomTypedField">
|
||||
<field name="customId"/>
|
||||
<!-- -->
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
UserTypedWithCustomTypedField:
|
||||
type: entity
|
||||
fields:
|
||||
customId: ~
|
||||
|
||||
It is perfectly valid to override even the "automatic" mapping rules mentioned above:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use App\DBAL\Type\CustomIntType;
|
||||
use Doctrine\ORM\Mapping\DefaultTypedFieldMapper;
|
||||
|
||||
$configuration->setTypedFieldMapper(new DefaultTypedFieldMapper([
|
||||
'int' => CustomIntType::class,
|
||||
]));
|
||||
|
||||
.. note::
|
||||
|
||||
If chained, once the first ``TypedFieldMapper`` assigns a type to a field, the ``DefaultTypedFieldMapper`` will
|
||||
ignore its mapping and not override it anymore (if it is later in the chain). See below for chaining type mappers.
|
||||
|
||||
|
||||
TypedFieldMapper interface
|
||||
-------------------------
|
||||
The interface ``Doctrine\ORM\Mapping\TypedFieldMapper`` allows you to implement your own
|
||||
typed field mapping logic. It consists of just one function
|
||||
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/**
|
||||
* Validates & completes the given field mapping based on typed property.
|
||||
*
|
||||
* @param array{fieldName: string, enumType?: string, type?: mixed} $mapping The field mapping to validate & complete.
|
||||
* @param \ReflectionProperty $field
|
||||
*
|
||||
* @return array{fieldName: string, enumType?: string, type?: mixed} The updated mapping.
|
||||
*/
|
||||
public function validateAndComplete(array $mapping, ReflectionProperty $field): array;
|
||||
|
||||
|
||||
ChainTypedFieldMapper
|
||||
---------------------
|
||||
|
||||
The class ``Doctrine\ORM\Mapping\ChainTypedFieldMapper`` allows you to chain multiple ``TypedFieldMapper`` instances.
|
||||
When being evaluated, the ``TypedFieldMapper::validateAndComplete`` is called in the order in which
|
||||
the instances were supplied to the ``ChainTypedFieldMapper`` constructor.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use App\DBAL\Type\CustomIntType;
|
||||
use Doctrine\ORM\Mapping\ChainTypedFieldMapper;
|
||||
use Doctrine\ORM\Mapping\DefaultTypedFieldMapper;
|
||||
|
||||
$configuration->setTypedFieldMapper(
|
||||
new ChainTypedFieldMapper(
|
||||
new DefaultTypedFieldMapper(['int' => CustomIntType::class,]),
|
||||
new CustomTypedFieldMapper()
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
Implementing a TypedFieldMapper
|
||||
-------------------------------
|
||||
|
||||
If you want to assign all ``BackedEnum`` fields to your custom ``BackedEnumDBALType`` or you want to use different
|
||||
DBAL types based on whether the entity field is nullable or not, you can achieve this by implementing your own
|
||||
typed field mapper.
|
||||
|
||||
You need to create a class which implements ``Doctrine\ORM\Mapping\TypedFieldMapper``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
final class CustomEnumTypedFieldMapper implements TypedFieldMapper
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validateAndComplete(array $mapping, ReflectionProperty $field): array
|
||||
{
|
||||
$type = $field->getType();
|
||||
|
||||
if (
|
||||
! isset($mapping['type'])
|
||||
&& ($type instanceof ReflectionNamedType)
|
||||
) {
|
||||
if (! $type->isBuiltin() && enum_exists($type->getName())) {
|
||||
$mapping['type'] = BackedEnumDBALType::class;
|
||||
}
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
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.
|
||||
@@ -37,8 +37,8 @@ will still end up with the same reference:
|
||||
public function testIdentityMapReference(): void
|
||||
{
|
||||
$objectA = $this->entityManager->getReference('EntityName', 1);
|
||||
// check for proxyinterface
|
||||
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $objectA);
|
||||
// check entity is not initialized
|
||||
$this->assertTrue($this->entityManager->isUninitializedObject($objectA));
|
||||
|
||||
$objectB = $this->entityManager->find('EntityName', 1);
|
||||
|
||||
@@ -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?".
|
||||
|
||||
@@ -137,7 +137,7 @@ optimize the performance of the Flush Operation:
|
||||
.. note::
|
||||
|
||||
Flush only a single entity with ``$entityManager->flush($entity)`` is deprecated and will be removed in ORM 3.0.
|
||||
(`Details <https://github.com/doctrine/orm/issues/8459>`_)
|
||||
(\ `Details <https://github.com/doctrine/orm/issues/8459>`_)
|
||||
|
||||
Query Internals
|
||||
---------------
|
||||
|
||||
@@ -718,6 +718,7 @@ methods:
|
||||
|
||||
* ``andX($arg1, $arg2, ...)``
|
||||
* ``orX($arg1, $arg2, ...)``
|
||||
* ``not($expression)``
|
||||
* ``eq($field, $value)``
|
||||
* ``gt($field, $value)``
|
||||
* ``lt($field, $value)``
|
||||
|
||||
@@ -162,28 +162,6 @@ your code. See the following code:
|
||||
echo "This will always be true!";
|
||||
}
|
||||
|
||||
A slice of the generated proxy classes code looks like the
|
||||
following piece of code. A real proxy class override ALL public
|
||||
methods along the lines of the ``getName()`` method shown below:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class UserProxy extends User implements Proxy
|
||||
{
|
||||
private function _load(): void
|
||||
{
|
||||
// lazy loading code
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
$this->_load();
|
||||
return parent::getName();
|
||||
}
|
||||
// .. other public methods of User
|
||||
}
|
||||
|
||||
.. warning::
|
||||
|
||||
Traversing the object graph for parts that are lazy-loaded will
|
||||
@@ -214,6 +192,11 @@ be properly synchronized with the database when
|
||||
database in the most efficient way and a single, short transaction,
|
||||
taking care of maintaining referential integrity.
|
||||
|
||||
.. note::
|
||||
|
||||
Do not make any assumptions in your code about the number of queries
|
||||
it takes to flush changes, about the ordering of ``INSERT``, ``UPDATE``
|
||||
and ``DELETE`` queries or the order in which entities will be processed.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -308,21 +291,58 @@ as follows:
|
||||
After an entity has been removed, its in-memory state is the same as
|
||||
before the removal, except for generated identifiers.
|
||||
|
||||
Removing an entity will also automatically delete any existing
|
||||
records in many-to-many join tables that link this entity. The
|
||||
action taken depends on the value of the ``@joinColumn`` mapping
|
||||
attribute "onDelete". Either Doctrine issues a dedicated ``DELETE``
|
||||
statement for records of each join table or it depends on the
|
||||
foreign key semantics of onDelete="CASCADE".
|
||||
During the ``EntityManager#flush()`` operation, the removed entity
|
||||
will also be removed from all collections in entities currently
|
||||
loaded into memory.
|
||||
|
||||
.. _remove_object_many_to_many_join_tables:
|
||||
|
||||
Join-table management when removing from many-to-many collections
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Regarding existing rows in many-to-many join tables that refer to
|
||||
an entity being removed, the following applies.
|
||||
|
||||
When the entity being removed does not declare the many-to-many association
|
||||
itself (that is, the many-to-many association is unidirectional and
|
||||
the entity is on the inverse side), the ORM has no reasonable way to
|
||||
detect associations targeting the entity's class. Thus, no ORM-level handling
|
||||
of join-table rows is attempted and database-level constraints apply.
|
||||
In case of database-level ``ON DELETE RESTRICT`` constraints, the
|
||||
``EntityManager#flush()`` operation may abort and a ``ConstraintViolationException``
|
||||
may be thrown. No in-memory collections will be modified in this case.
|
||||
With ``ON DELETE CASCADE``, the RDBMS will take care of removing rows
|
||||
from join tables.
|
||||
|
||||
When the entity being removed is part of bi-directional many-to-many
|
||||
association, either as the owning or inverse side, the ORM will
|
||||
delete rows from join tables before removing the entity itself. That means
|
||||
database-level ``ON DELETE RESTRICT`` constraints on join tables are not
|
||||
effective, since the join table rows are removed first. Removal of join table
|
||||
rows happens through specialized methods in entity and collection persister
|
||||
classes and take one query per entity and join table. In case the association
|
||||
uses a ``@JoinColumn`` configuration with ``onDelete="CASCADE"``, instead
|
||||
of using a dedicated ``DELETE`` query the database-level operation will be
|
||||
relied upon.
|
||||
|
||||
.. note::
|
||||
|
||||
In case you rely on database-level ``ON DELETE RESTRICT`` constraints,
|
||||
be aware that by making many-to-many associations bidirectional the
|
||||
assumed protection may be lost.
|
||||
|
||||
|
||||
Performance of different deletion strategies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Deleting an object with all its associated objects can be achieved
|
||||
in multiple ways with very different performance impacts.
|
||||
|
||||
|
||||
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM
|
||||
will fetch this association. If its a Single association it will
|
||||
pass this entity to
|
||||
``EntityManager#remove()``. If the association is a collection, Doctrine will loop over all its elements and pass them to``EntityManager#remove()``.
|
||||
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM will
|
||||
fetch this association. If it's a Single association it will pass
|
||||
this entity to ``EntityManager#remove()``. If the association is a
|
||||
collection, Doctrine will loop over all its elements and pass them to
|
||||
``EntityManager#remove()``.
|
||||
In both cases the cascade remove semantics are applied recursively.
|
||||
For large object graphs this removal strategy can be very costly.
|
||||
2. Using a DQL ``DELETE`` statement allows you to delete multiple
|
||||
@@ -414,14 +434,6 @@ Example:
|
||||
// $entity now refers to the fully managed copy returned by the merge operation.
|
||||
// The EntityManager $em now manages the persistence of $entity as usual.
|
||||
|
||||
.. note::
|
||||
|
||||
When you want to serialize/unserialize entities you
|
||||
have to make all entity properties protected, never private. The
|
||||
reason for this is, if you serialize a class that was a proxy
|
||||
instance before, the private variables won't be serialized and a
|
||||
PHP Notice is thrown.
|
||||
|
||||
|
||||
The semantics of the merge operation, applied to an entity X, are
|
||||
as follows:
|
||||
@@ -771,6 +783,23 @@ and these associations are mapped as EAGER, they will automatically
|
||||
be loaded together with the entity being queried and is thus
|
||||
immediately available to your application.
|
||||
|
||||
Eager Loading can also be configured at runtime through
|
||||
``AbstractQuery::setFetchMode`` in DQL or Native Queries.
|
||||
|
||||
Eager loading for many-to-one and one-to-one associations is using either a
|
||||
LEFT JOIN or a second query for fetching the related entity eagerly.
|
||||
|
||||
Eager loading for many-to-one associations uses a second query to load
|
||||
the collections for several entities at the same time.
|
||||
|
||||
When many-to-many, one-to-one or one-to-many associations are eagerly loaded,
|
||||
then the global batch size configuration is used to avoid IN(?) queries with
|
||||
too many arguments. The default batch size is 100 and can be changed with
|
||||
``Configuration::setEagerFetchBatchSize()``.
|
||||
|
||||
For eagerly loaded Many-To-Many associations one query has to be made for each
|
||||
collection.
|
||||
|
||||
By Lazy Loading
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ setup for the latest code in trunk.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
...
|
||||
@@ -102,9 +102,9 @@ of several common elements:
|
||||
|
||||
// Doctrine.Tests.ORM.Mapping.User.dcm.xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\ORM\Mapping\User" table="cms_users">
|
||||
@@ -769,9 +769,9 @@ entity relationship. You can define this in XML with the "association-key" attri
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Application\Model\ArticleAttribute">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
YAML Mapping
|
||||
============
|
||||
|
||||
.. note::
|
||||
.. 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.
|
||||
|
||||
|
||||
@@ -1,84 +1,77 @@
|
||||
.. 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-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
|
||||
|
||||
.. 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/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/implementing-wakeup-or-clone
|
||||
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/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
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
Welcome to Doctrine 2 ORM's documentation!
|
||||
==========================================
|
||||
|
||||
Tutorials
|
||||
---------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
tutorials/getting-started
|
||||
tutorials/getting-started-database
|
||||
tutorials/getting-started-models
|
||||
tutorials/working-with-indexed-associations
|
||||
tutorials/extra-lazy-associations
|
||||
tutorials/composite-primary-keys
|
||||
tutorials/ordered-associations
|
||||
tutorials/override-field-association-mappings-in-subclasses
|
||||
tutorials/pagination.rst
|
||||
tutorials/embeddables.rst
|
||||
|
||||
Reference Guide
|
||||
---------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:numbered:
|
||||
|
||||
reference/architecture
|
||||
reference/configuration.rst
|
||||
reference/faq
|
||||
reference/basic-mapping
|
||||
reference/association-mapping
|
||||
reference/inheritance-mapping
|
||||
reference/working-with-objects
|
||||
reference/working-with-associations
|
||||
reference/events
|
||||
reference/unitofwork
|
||||
reference/unitofwork-associations
|
||||
reference/transactions-and-concurrency
|
||||
reference/batch-processing
|
||||
reference/dql-doctrine-query-language
|
||||
reference/query-builder
|
||||
reference/native-sql
|
||||
reference/change-tracking-policies
|
||||
reference/partial-objects
|
||||
reference/annotations-reference
|
||||
reference/attributes-reference
|
||||
reference/xml-mapping
|
||||
reference/yaml-mapping
|
||||
reference/php-mapping
|
||||
reference/caching
|
||||
reference/improving-performance
|
||||
reference/tools
|
||||
reference/metadata-drivers
|
||||
reference/best-practices
|
||||
reference/limitations-and-known-issues
|
||||
tutorials/pagination
|
||||
reference/filters
|
||||
reference/namingstrategy
|
||||
reference/advanced-configuration
|
||||
reference/second-level-cache
|
||||
reference/security
|
||||
|
||||
|
||||
Cookbook
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
cookbook/aggregate-fields
|
||||
cookbook/custom-mapping-types
|
||||
cookbook/decorator-pattern
|
||||
cookbook/dql-custom-walkers
|
||||
cookbook/dql-user-defined-functions
|
||||
cookbook/implementing-arrayaccess-for-domain-objects
|
||||
cookbook/implementing-the-notify-changetracking-policy
|
||||
cookbook/implementing-wakeup-or-clone
|
||||
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
|
||||
|
||||
@@ -32,9 +32,9 @@ and year of production as primary keys:
|
||||
class Car
|
||||
{
|
||||
public function __construct(
|
||||
#[Id, Column(type: 'string')]
|
||||
#[Id, Column]
|
||||
private string $name,
|
||||
#[Id, Column(type: 'integer')]
|
||||
#[Id, Column]
|
||||
private int $year,
|
||||
) {
|
||||
}
|
||||
@@ -82,33 +82,12 @@ and year of production as primary keys:
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
private int|null $id = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class Address
|
||||
{
|
||||
/** @Id @OneToOne(targetEntity="User") */
|
||||
private User|null $user = null;
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="VehicleCatalogue\Model\Car">
|
||||
@@ -152,7 +131,7 @@ And for querying you can use arrays to both DQL and EntityRepositories:
|
||||
|
||||
$dql = "SELECT c FROM VehicleCatalogue\Model\Car c WHERE c.id = ?1";
|
||||
$audi = $em->createQuery($dql)
|
||||
->setParameter(1, array("name" => "Audi A8", "year" => 2010))
|
||||
->setParameter(1, ["name" => "Audi A8", "year" => 2010])
|
||||
->getSingleResult();
|
||||
|
||||
You can also use this entity in associations. Doctrine will then generate two foreign keys one for ``name``
|
||||
@@ -190,7 +169,52 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
namespace Application\Model;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
#[Entity]
|
||||
class Article
|
||||
{
|
||||
#[Id, Column, GeneratedValue]
|
||||
private int|null $id = null;
|
||||
#[Column]
|
||||
private string $title;
|
||||
|
||||
/** @var ArrayCollection<string, ArticleAttribute> */
|
||||
#[OneToMany(targetEntity: ArticleAttribute::class, mappedBy: 'article', cascade: ['ALL'], indexBy: 'attribute')]
|
||||
private Collection $attributes;
|
||||
|
||||
public function addAttribute(string $name, string $value): void
|
||||
{
|
||||
$this->attributes[$name] = new ArticleAttribute($name, $value, $this);
|
||||
}
|
||||
}
|
||||
|
||||
#[Entity]
|
||||
class ArticleAttribute
|
||||
{
|
||||
#[Id, ManyToOne(targetEntity: Article::class, inversedBy: 'attributes')]
|
||||
private Article $article;
|
||||
|
||||
#[Id, Column]
|
||||
private string $attribute;
|
||||
|
||||
#[Column]
|
||||
private string $value;
|
||||
|
||||
public function __construct(string $name, string $value, Article $article)
|
||||
{
|
||||
$this->attribute = $name;
|
||||
$this->value = $value;
|
||||
$this->article = $article;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
namespace Application\Model;
|
||||
@@ -241,56 +265,11 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: attribute
|
||||
|
||||
<?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;
|
||||
|
||||
/** @var ArrayCollection<string, ArticleAttribute> */
|
||||
#[OneToMany(targetEntity: ArticleAttribute::class, mappedBy: 'article', cascade: ['ALL'], indexBy: 'attribute')]
|
||||
private Collection $attributes;
|
||||
|
||||
public function addAttribute(string $name, ArticleAttribute $value): void
|
||||
{
|
||||
$this->attributes[$name] = new ArticleAttribute($name, $value, $this);
|
||||
}
|
||||
}
|
||||
|
||||
#[Entity]
|
||||
class ArticleAttribute
|
||||
{
|
||||
#[Id, ManyToOne(targetEntity: Article::class, inversedBy: 'attributes')]
|
||||
private Article $article;
|
||||
|
||||
#[Id, Column(type: 'string')]
|
||||
private string $attribute;
|
||||
|
||||
#[Column(type: 'string')]
|
||||
private string $value;
|
||||
|
||||
public function __construct(string $name, string $value, Article $article)
|
||||
{
|
||||
$this->attribute = $name;
|
||||
$this->value = $value;
|
||||
$this->article = $article;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Application\Model\ArticleAttribute">
|
||||
@@ -338,7 +317,7 @@ One good example for this is a user-address relationship:
|
||||
#[Entity]
|
||||
class User
|
||||
{
|
||||
#[Id, Column(type: 'integer'), GeneratedValue]
|
||||
#[Id, Column, GeneratedValue]
|
||||
private int|null $id = null;
|
||||
}
|
||||
|
||||
@@ -386,18 +365,18 @@ of products purchased and maybe even the current price.
|
||||
#[Entity]
|
||||
class Order
|
||||
{
|
||||
#[Id, Column(type: 'integer'), GeneratedValue]
|
||||
#[Id, Column, GeneratedValue]
|
||||
private int|null $id = null;
|
||||
|
||||
/** @var ArrayCollection<int, OrderItem> */
|
||||
#[OneToMany(targetEntity: OrderItem::class, mappedBy: 'order')]
|
||||
private Collection $items;
|
||||
|
||||
#[Column(type: 'boolean')]
|
||||
#[Column]
|
||||
private bool $paid = false;
|
||||
#[Column(type: 'boolean')]
|
||||
#[Column]
|
||||
private bool $shipped = false;
|
||||
#[Column(type: 'datetime')]
|
||||
#[Column]
|
||||
private DateTime $created;
|
||||
|
||||
public function __construct(
|
||||
@@ -412,16 +391,16 @@ of products purchased and maybe even the current price.
|
||||
#[Entity]
|
||||
class Product
|
||||
{
|
||||
#[Id, Column(type: 'integer'), GeneratedValue]
|
||||
#[Id, Column, GeneratedValue]
|
||||
private int|null $id = null;
|
||||
|
||||
#[Column(type: 'string')]
|
||||
#[Column]
|
||||
private string $name;
|
||||
|
||||
#[Column(type: 'decimal')]
|
||||
private float $currentPrice;
|
||||
#[Column]
|
||||
private int $currentPrice;
|
||||
|
||||
public function getCurrentPrice(): float
|
||||
public function getCurrentPrice(): int
|
||||
{
|
||||
return $this->currentPrice;
|
||||
}
|
||||
@@ -436,11 +415,11 @@ of products purchased and maybe even the current price.
|
||||
#[Id, ManyToOne(targetEntity: Product::class)]
|
||||
private Product|null $product = null;
|
||||
|
||||
#[Column(type: 'integer')]
|
||||
#[Column]
|
||||
private int $amount = 1;
|
||||
|
||||
#[Column(type: 'decimal')]
|
||||
private float $offeredPrice;
|
||||
#[Column]
|
||||
private int $offeredPrice;
|
||||
|
||||
public function __construct(Order $order, Product $product, int $amount = 1)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ can be called without triggering a full load of the collection:
|
||||
- ``Collection#containsKey($key)``
|
||||
- ``Collection#count()``
|
||||
- ``Collection#get($key)``
|
||||
- ``Collection#isEmpty()``
|
||||
- ``Collection#slice($offset, $length = null)``
|
||||
|
||||
For each of the above methods the following semantics apply:
|
||||
@@ -85,9 +86,9 @@ switch to extra lazy as shown in these examples:
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\CMS\CmsGroup">
|
||||
|
||||
@@ -22,5 +22,5 @@ In this workflow you would modify the database schema first and then
|
||||
regenerate the PHP code to use with this schema. You need a flexible
|
||||
code-generator for this task.
|
||||
|
||||
We spinned off a subproject, Doctrine CodeGenerator, that will fill this gap and
|
||||
We spun off a subproject, Doctrine CodeGenerator, that will fill this gap and
|
||||
allow you to do *Database First* development.
|
||||
|
||||
@@ -18,7 +18,7 @@ before. There are some prerequisites for the tutorial that have to be
|
||||
installed:
|
||||
|
||||
- PHP (latest stable version)
|
||||
- Composer Package Manager (`Install Composer
|
||||
- Composer Package Manager (\ `Install Composer
|
||||
<https://getcomposer.org/doc/00-intro.md>`_)
|
||||
|
||||
The code of this tutorial is `available on Github <https://github.com/doctrine/doctrine2-orm-tutorial>`_.
|
||||
@@ -43,14 +43,15 @@ What are Entities?
|
||||
|
||||
Entities are PHP Objects that can be identified over many requests
|
||||
by a unique identifier or primary key. These classes don't need to extend any
|
||||
abstract base class or interface. An entity class must not be final
|
||||
or contain final methods. Additionally it must not implement
|
||||
**clone** nor **wakeup**, unless it :doc:`does so safely <../cookbook/implementing-wakeup-or-clone>`.
|
||||
abstract base class or interface.
|
||||
|
||||
An entity contains persistable properties. A persistable property
|
||||
is an instance variable of the entity that is saved into and retrieved from the database
|
||||
by Doctrine's data mapping capabilities.
|
||||
|
||||
An entity class must not be final nor read-only, although
|
||||
it can contain final methods or read-only properties.
|
||||
|
||||
An Example Model: Bug Tracker
|
||||
-----------------------------
|
||||
|
||||
@@ -101,8 +102,7 @@ Install Doctrine using the Composer Dependency Management tool, by calling:
|
||||
This will install the packages Doctrine Common, Doctrine DBAL, Doctrine ORM,
|
||||
into the ``vendor`` directory.
|
||||
|
||||
Add the following directories:
|
||||
::
|
||||
Add the following directories::
|
||||
|
||||
doctrine2-tutorial
|
||||
|-- config
|
||||
@@ -136,6 +136,7 @@ step:
|
||||
|
||||
<?php
|
||||
// bootstrap.php
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\ORMSetup;
|
||||
|
||||
@@ -143,7 +144,7 @@ step:
|
||||
|
||||
// Create a simple "default" Doctrine ORM configuration for Attributes
|
||||
$config = ORMSetup::createAttributeMetadataConfiguration(
|
||||
paths: array(__DIR__."/src"),
|
||||
paths: [__DIR__ . '/src'],
|
||||
isDevMode: true,
|
||||
);
|
||||
// or if you prefer annotation, YAML or XML
|
||||
@@ -152,7 +153,7 @@ step:
|
||||
// isDevMode: true,
|
||||
// );
|
||||
// $config = ORMSetup::createXMLMetadataConfiguration(
|
||||
// paths: array(__DIR__."/config/xml"),
|
||||
// paths: [__DIR__ . '/config/xml'],
|
||||
// isDevMode: true,
|
||||
//);
|
||||
// $config = ORMSetup::createYAMLMetadataConfiguration(
|
||||
@@ -160,14 +161,14 @@ step:
|
||||
// isDevMode: true,
|
||||
// );
|
||||
|
||||
// database configuration parameters
|
||||
$conn = array(
|
||||
// configuring the database connection
|
||||
$connection = DriverManager::getConnection([
|
||||
'driver' => 'pdo_sqlite',
|
||||
'path' => __DIR__ . '/db.sqlite',
|
||||
);
|
||||
], $config);
|
||||
|
||||
// obtaining the entity manager
|
||||
$entityManager = EntityManager::create($conn, $config);
|
||||
$entityManager = new EntityManager($connection, $config);
|
||||
|
||||
.. note::
|
||||
The YAML driver is deprecated and will be removed in version 3.0.
|
||||
@@ -320,7 +321,7 @@ data in your storage, and later in your application when the data is loaded agai
|
||||
.. note::
|
||||
|
||||
This method, although very common, is inappropriate for Domain Driven
|
||||
Design (`DDD <https://en.wikipedia.org/wiki/Domain-driven_design>`)
|
||||
Design (\ `DDD <https://en.wikipedia.org/wiki/Domain-driven_design>`_)
|
||||
where methods should represent real business operations and not simple
|
||||
property change, And business invariants should be maintained both in the
|
||||
application state (entities in this case) and in the database, with no
|
||||
@@ -447,7 +448,7 @@ entity.
|
||||
|
||||
.. note::
|
||||
|
||||
A `DTO <https://en.wikipedia.org/wiki/Data_transfer_object>` is an object
|
||||
A `DTO <https://en.wikipedia.org/wiki/Data_transfer_object>`_ is an object
|
||||
that only carries data without any logic. Its only goal is to be transferred
|
||||
from one service to another.
|
||||
A ``DTO`` often represents data sent by a client and that has to be validated,
|
||||
@@ -556,10 +557,10 @@ methods, but you only need to choose one.
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/Product.dcm.xml -->
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Product" table="products">
|
||||
<id name="id" type="integer">
|
||||
@@ -734,7 +735,7 @@ classes. We'll store them in ``src/Bug.php`` and ``src/User.php``, respectively.
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
#[ORM\GeneratedValue]
|
||||
private int $id;
|
||||
private int|null $id;
|
||||
|
||||
#[ORM\Column(type: 'string')]
|
||||
private string $description;
|
||||
@@ -888,18 +889,6 @@ domain model to match the requirements:
|
||||
understand the changes that have happened to the collection that are
|
||||
noteworthy for persistence.
|
||||
|
||||
.. warning::
|
||||
|
||||
Lazy load proxies always contain an instance of
|
||||
Doctrine's EntityManager and all its dependencies. Therefore a
|
||||
``var_dump()`` will possibly dump a very large recursive structure
|
||||
which is impossible to render and read. You have to use
|
||||
``Doctrine\Common\Util\Debug::dump()`` to restrict the dumping to a
|
||||
human readable level. Additionally you should be aware that dumping
|
||||
the EntityManager to a Browser may take several minutes, and the
|
||||
``Debug::dump()`` method just ignores any occurrences of it in Proxy
|
||||
instances.
|
||||
|
||||
Because we only work with collections for the references we must be
|
||||
careful to implement a bidirectional reference in the domain model.
|
||||
The concept of owning or inverse side of a relation is central to
|
||||
@@ -1149,10 +1138,10 @@ the ``Product`` before:
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/Bug.dcm.xml -->
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Bug" table="bugs">
|
||||
<id name="id" type="integer">
|
||||
@@ -1210,21 +1199,21 @@ which translates the YYYY-mm-dd HH:mm:ss database format
|
||||
into a PHP DateTime instance and back.
|
||||
|
||||
After the field definitions, the two qualified references to the
|
||||
user entity are defined. They are created by the ``many-to-one``
|
||||
tag. The class name of the related entity has to be specified with
|
||||
the ``target-entity`` attribute, which is enough information for
|
||||
the database mapper to access the foreign-table. Since
|
||||
user entity are defined. They are created by the ``ManyToOne``
|
||||
attribute. The class name of the related entity has to be specified with
|
||||
the ``targetEntity`` parameter, which is enough information for
|
||||
the database mapper to access the foreign table. Since
|
||||
``reporter`` and ``engineer`` are on the owning side of a
|
||||
bi-directional relation, we also have to specify the ``inversed-by``
|
||||
attribute. They have to point to the field names on the inverse
|
||||
side of the relationship. We will see in the next example that the ``inversed-by``
|
||||
attribute has a counterpart ``mapped-by`` which makes that
|
||||
bi-directional relation, we also have to specify the ``inversedBy``
|
||||
parameter. They have to point to the field names on the inverse
|
||||
side of the relationship. We will see in the next example that the ``inversedBy``
|
||||
parameter has a counterpart ``mappedBy`` which makes that
|
||||
the inverse side.
|
||||
|
||||
The last definition is for the ``Bug#products`` collection. It
|
||||
holds all products where the specific bug occurs. Again
|
||||
you have to define the ``target-entity`` and ``field`` attributes
|
||||
on the ``many-to-many`` tag.
|
||||
you have to define the ``targetEntity`` and ``field`` parameters
|
||||
on the ``ManyToMany`` attribute.
|
||||
|
||||
Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
|
||||
@@ -1304,10 +1293,10 @@ Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/User.dcm.xml -->
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="User" table="users">
|
||||
<id name="id" type="integer">
|
||||
@@ -1347,15 +1336,14 @@ Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
targetEntity: Bug
|
||||
mappedBy: engineer
|
||||
|
||||
Here are some new things to mention about the ``one-to-many`` tags.
|
||||
Here are some new things to mention about the ``OneToMany`` attribute.
|
||||
Remember that we discussed about the inverse and owning side. Now
|
||||
both reportedBugs and assignedBugs are inverse relations, which
|
||||
means the join details have already been defined on the owning
|
||||
side. Therefore we only have to specify the property on the Bug
|
||||
class that holds the owning sides.
|
||||
|
||||
Update your database schema by running:
|
||||
::
|
||||
Update your database schema by running::
|
||||
|
||||
$ php bin/doctrine orm:schema-tool:update --force
|
||||
|
||||
@@ -1588,39 +1576,8 @@ The output of the engineer’s name is fetched from the database! What is happen
|
||||
|
||||
Since we only retrieved the bug by primary key both the engineer and reporter
|
||||
are not immediately loaded from the database but are replaced by LazyLoading
|
||||
proxies. These proxies will load behind the scenes, when the first method
|
||||
is called on them.
|
||||
|
||||
Sample code of this proxy generated code can be found in the specified Proxy
|
||||
Directory, it looks like:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace MyProject\Proxies;
|
||||
|
||||
/**
|
||||
* THIS CLASS WAS GENERATED BY THE DOCTRINE ORM. DO NOT EDIT THIS FILE.
|
||||
**/
|
||||
class UserProxy extends \User implements \Doctrine\ORM\Proxy\Proxy
|
||||
{
|
||||
// .. lazy load code here
|
||||
|
||||
public function addReportedBug($bug)
|
||||
{
|
||||
$this->_load();
|
||||
return parent::addReportedBug($bug);
|
||||
}
|
||||
|
||||
public function assignedToBug($bug)
|
||||
{
|
||||
$this->_load();
|
||||
return parent::assignedToBug($bug);
|
||||
}
|
||||
}
|
||||
|
||||
See how upon each method call the proxy is lazily loaded from the
|
||||
database?
|
||||
proxies. These proxies will load behind the scenes, when attempting to access
|
||||
any of their un-initialized state.
|
||||
|
||||
The call prints:
|
||||
|
||||
@@ -1860,9 +1817,9 @@ we have to adjust the metadata slightly.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Bug" table="bugs" repository-class="BugRepository">
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -15,7 +15,7 @@ has a very simple API and implements the SPL interfaces ``Countable`` and
|
||||
->setFirstResult(0)
|
||||
->setMaxResults(100);
|
||||
|
||||
$paginator = new Paginator($query, $fetchJoinCollection = true);
|
||||
$paginator = new Paginator($query, fetchJoinCollection: true);
|
||||
|
||||
$c = count($paginator);
|
||||
foreach ($paginator as $post) {
|
||||
@@ -36,10 +36,25 @@ correct result:
|
||||
|
||||
This behavior is only necessary if you actually fetch join a to-many
|
||||
collection. You can disable this behavior by setting the
|
||||
``$fetchJoinCollection`` flag to ``false``; in that case only 2 instead of the 3 queries
|
||||
``fetchJoinCollection`` argument to ``false``; in that case only 2 instead of the 3 queries
|
||||
described are executed. We hope to automate the detection for this in
|
||||
the future.
|
||||
|
||||
.. note::
|
||||
|
||||
``$fetchJoinCollection`` flag set to ``true`` might affect results if you use aggregations in your query.
|
||||
``fetchJoinCollection`` argument set to ``true`` might affect results if you use aggregations in your query.
|
||||
|
||||
By using the ``Paginator::HINT_ENABLE_DISTINCT`` you can instruct doctrine that the query to be executed
|
||||
will not produce "duplicate" rows (only to-one relations are joined), thus the SQL limit will work as expected.
|
||||
In this way the `DISTINCT` keyword will be omitted and can bring important performance improvements.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
|
||||
$dql = "SELECT u, p FROM User u JOIN u.mainPicture p";
|
||||
$query = $entityManager->createQuery($dql)
|
||||
->setHint(Paginator::HINT_ENABLE_DISTINCT, false)
|
||||
->setFirstResult(0)
|
||||
->setMaxResults(100);
|
||||
|
||||
@@ -31,169 +31,18 @@ You can map indexed associations by adding:
|
||||
The code and mappings for the Market entity looks like this:
|
||||
|
||||
.. configuration-block::
|
||||
.. code-block:: attribute
|
||||
.. literalinclude:: working-with-indexed-associations/Market.php
|
||||
:language: attribute
|
||||
|
||||
<?php
|
||||
namespace Doctrine\Tests\Models\StockExchange;
|
||||
.. literalinclude:: working-with-indexed-associations/Market-annotations.php
|
||||
:language: annotation
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
.. literalinclude:: working-with-indexed-associations/market.xml
|
||||
:language: xml
|
||||
|
||||
#[Entity]
|
||||
#[Table(name: 'exchange_markets')]
|
||||
class Market
|
||||
{
|
||||
#[Id, Column(type: 'integer'), GeneratedValue]
|
||||
private int|null $id = null;
|
||||
.. literalinclude:: working-with-indexed-associations/market.yaml
|
||||
:language: yaml
|
||||
|
||||
#[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="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<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
|
||||
|
||||
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)``
|
||||
@@ -278,9 +127,9 @@ here are the code and mappings for it:
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\StockExchange\Stock">
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
@@ -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="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>
|
||||
@@ -0,0 +1,15 @@
|
||||
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
|
||||
@@ -148,7 +148,6 @@
|
||||
<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:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
@@ -226,22 +225,13 @@
|
||||
|
||||
<xs:complexType name="mapped-superclass" >
|
||||
<xs:complexContent>
|
||||
<xs:extension base="orm:entity">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:extension>
|
||||
<xs:extension base="orm:entity"/>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="embeddable">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="orm:entity">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
</xs:extension>
|
||||
<xs:extension base="orm:entity"/>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
@@ -302,7 +292,7 @@
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
|
||||
<xs:attribute name="type" type="orm:type" default="string" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="unique" type="xs:boolean" default="false" />
|
||||
@@ -330,6 +320,7 @@
|
||||
|
||||
<xs:complexType name="discriminator-column">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
@@ -337,6 +328,7 @@
|
||||
<xs:attribute name="field-name" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="column-definition" type="xs:string" />
|
||||
<xs:attribute name="enum-type" type="xs:string" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
@@ -383,7 +375,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>
|
||||
@@ -413,7 +405,7 @@
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="type" type="orm:type" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="association-key" type="xs:boolean" default="false" />
|
||||
@@ -445,6 +437,13 @@
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="type" id="type">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:pattern value="([a-zA-Z_u01-uff][a-zA-Z0-9_u01-uff]+)|(\c+)" id="type.class.pattern">
|
||||
</xs:pattern>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="inverse-join-columns">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />
|
||||
@@ -556,7 +555,6 @@
|
||||
<xs:choice minOccurs="0" maxOccurs="1">
|
||||
<xs:element name="join-column" type="orm:join-column"/>
|
||||
<xs:element name="join-columns" type="orm:join-columns"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
@@ -574,7 +572,6 @@
|
||||
<xs:choice minOccurs="0" maxOccurs="1">
|
||||
<xs:element name="join-column" type="orm:join-column"/>
|
||||
<xs:element name="join-columns" type="orm:join-columns"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
@@ -629,7 +626,7 @@
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
|
||||
<xs:attribute name="type" type="orm:type" default="string" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="unique" type="xs:boolean" default="false" />
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
/**
|
||||
* Defines entity / collection / query key to be stored in the cache region.
|
||||
* Allows multiple roles to be stored in the same cache region.
|
||||
*/
|
||||
abstract class CacheKey
|
||||
{
|
||||
/**
|
||||
* Unique identifier
|
||||
*
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
*/
|
||||
public $hash;
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal;
|
||||
|
||||
use stdClass;
|
||||
|
||||
use function array_reverse;
|
||||
|
||||
/**
|
||||
* CommitOrderCalculator implements topological sorting, which is an ordering
|
||||
* algorithm for directed graphs (DG) and/or directed acyclic graphs (DAG) by
|
||||
* using a depth-first searching (DFS) to traverse the graph built in memory.
|
||||
* This algorithm have a linear running time based on nodes (V) and dependency
|
||||
* between the nodes (E), resulting in a computational complexity of O(V + E).
|
||||
*/
|
||||
class CommitOrderCalculator
|
||||
{
|
||||
public const NOT_VISITED = 0;
|
||||
public const IN_PROGRESS = 1;
|
||||
public const VISITED = 2;
|
||||
|
||||
/**
|
||||
* Matrix of nodes (aka. vertex).
|
||||
* Keys are provided hashes and values are the node definition objects.
|
||||
*
|
||||
* The node state definition contains the following properties:
|
||||
*
|
||||
* - <b>state</b> (integer)
|
||||
* Whether the node is NOT_VISITED or IN_PROGRESS
|
||||
*
|
||||
* - <b>value</b> (object)
|
||||
* Actual node value
|
||||
*
|
||||
* - <b>dependencyList</b> (array<string>)
|
||||
* Map of node dependencies defined as hashes.
|
||||
*
|
||||
* @var array<stdClass>
|
||||
*/
|
||||
private $nodeList = [];
|
||||
|
||||
/**
|
||||
* Volatile variable holding calculated nodes during sorting process.
|
||||
*
|
||||
* @psalm-var list<object>
|
||||
*/
|
||||
private $sortedNodeList = [];
|
||||
|
||||
/**
|
||||
* Checks for node (vertex) existence in graph.
|
||||
*
|
||||
* @param string $hash
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasNode($hash)
|
||||
{
|
||||
return isset($this->nodeList[$hash]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new node (vertex) to the graph, assigning its hash and value.
|
||||
*
|
||||
* @param string $hash
|
||||
* @param object $node
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addNode($hash, $node)
|
||||
{
|
||||
$vertex = new stdClass();
|
||||
|
||||
$vertex->hash = $hash;
|
||||
$vertex->state = self::NOT_VISITED;
|
||||
$vertex->value = $node;
|
||||
$vertex->dependencyList = [];
|
||||
|
||||
$this->nodeList[$hash] = $vertex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new dependency (edge) to the graph using their hashes.
|
||||
*
|
||||
* @param string $fromHash
|
||||
* @param string $toHash
|
||||
* @param int $weight
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addDependency($fromHash, $toHash, $weight)
|
||||
{
|
||||
$vertex = $this->nodeList[$fromHash];
|
||||
$edge = new stdClass();
|
||||
|
||||
$edge->from = $fromHash;
|
||||
$edge->to = $toHash;
|
||||
$edge->weight = $weight;
|
||||
|
||||
$vertex->dependencyList[$toHash] = $edge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a valid order list of all current nodes.
|
||||
* The desired topological sorting is the reverse post order of these searches.
|
||||
*
|
||||
* {@internal Highly performance-sensitive method.}
|
||||
*
|
||||
* @psalm-return list<object>
|
||||
*/
|
||||
public function sort()
|
||||
{
|
||||
foreach ($this->nodeList as $vertex) {
|
||||
if ($vertex->state !== self::NOT_VISITED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->visit($vertex);
|
||||
}
|
||||
|
||||
$sortedList = $this->sortedNodeList;
|
||||
|
||||
$this->nodeList = [];
|
||||
$this->sortedNodeList = [];
|
||||
|
||||
return array_reverse($sortedList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit a given node definition for reordering.
|
||||
*
|
||||
* {@internal Highly performance-sensitive method.}
|
||||
*/
|
||||
private function visit(stdClass $vertex): void
|
||||
{
|
||||
$vertex->state = self::IN_PROGRESS;
|
||||
|
||||
foreach ($vertex->dependencyList as $edge) {
|
||||
$adjacentVertex = $this->nodeList[$edge->to];
|
||||
|
||||
switch ($adjacentVertex->state) {
|
||||
case self::VISITED:
|
||||
// Do nothing, since node was already visited
|
||||
break;
|
||||
|
||||
case self::IN_PROGRESS:
|
||||
if (
|
||||
isset($adjacentVertex->dependencyList[$vertex->hash]) &&
|
||||
$adjacentVertex->dependencyList[$vertex->hash]->weight < $edge->weight
|
||||
) {
|
||||
// If we have some non-visited dependencies in the in-progress dependency, we
|
||||
// need to visit them before adding the node.
|
||||
foreach ($adjacentVertex->dependencyList as $adjacentEdge) {
|
||||
$adjacentEdgeVertex = $this->nodeList[$adjacentEdge->to];
|
||||
|
||||
if ($adjacentEdgeVertex->state === self::NOT_VISITED) {
|
||||
$this->visit($adjacentEdgeVertex);
|
||||
}
|
||||
}
|
||||
|
||||
$adjacentVertex->state = self::VISITED;
|
||||
|
||||
$this->sortedNodeList[] = $adjacentVertex->value;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case self::NOT_VISITED:
|
||||
$this->visit($adjacentVertex);
|
||||
}
|
||||
}
|
||||
|
||||
if ($vertex->state !== self::VISITED) {
|
||||
$vertex->state = self::VISITED;
|
||||
|
||||
$this->sortedNodeList[] = $vertex->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @todo remove or rename ClassMetadataInfo to ClassMetadata
|
||||
* @template-covariant T of object
|
||||
* @template-extends ClassMetadataInfo<T>
|
||||
*/
|
||||
class ClassMetadata extends ClassMetadataInfo
|
||||
{
|
||||
/**
|
||||
* Repeating the ClassMetadataInfo constructor to infer correctly the template with PHPStan
|
||||
*
|
||||
* @see https://github.com/doctrine/orm/issues/8709
|
||||
*
|
||||
* @param string $entityName The name of the entity class the new instance is used for.
|
||||
* @psalm-param class-string<T> $entityName
|
||||
*/
|
||||
public function __construct($entityName, ?NamingStrategy $namingStrategy = null)
|
||||
{
|
||||
parent::__construct($entityName, $namingStrategy);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use Attribute;
|
||||
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
final class DiscriminatorColumn implements Annotation
|
||||
{
|
||||
/** @var string|null */
|
||||
public $name;
|
||||
|
||||
/** @var string|null */
|
||||
public $type;
|
||||
|
||||
/** @var int|null */
|
||||
public $length;
|
||||
|
||||
/**
|
||||
* Field name used in non-object hydration (array/scalar).
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $fieldName;
|
||||
|
||||
/** @var string */
|
||||
public $columnDefinition;
|
||||
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
?string $type = null,
|
||||
?int $length = null,
|
||||
?string $columnDefinition = null
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->type = $type;
|
||||
$this->length = $length;
|
||||
$this->columnDefinition = $columnDefinition;
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../Annotation.php';
|
||||
require_once __DIR__ . '/../Entity.php';
|
||||
require_once __DIR__ . '/../Embeddable.php';
|
||||
require_once __DIR__ . '/../Embedded.php';
|
||||
require_once __DIR__ . '/../MappedSuperclass.php';
|
||||
require_once __DIR__ . '/../InheritanceType.php';
|
||||
require_once __DIR__ . '/../DiscriminatorColumn.php';
|
||||
require_once __DIR__ . '/../DiscriminatorMap.php';
|
||||
require_once __DIR__ . '/../Id.php';
|
||||
require_once __DIR__ . '/../GeneratedValue.php';
|
||||
require_once __DIR__ . '/../Version.php';
|
||||
require_once __DIR__ . '/../JoinColumn.php';
|
||||
require_once __DIR__ . '/../JoinColumns.php';
|
||||
require_once __DIR__ . '/../Column.php';
|
||||
require_once __DIR__ . '/../OneToOne.php';
|
||||
require_once __DIR__ . '/../OneToMany.php';
|
||||
require_once __DIR__ . '/../ManyToOne.php';
|
||||
require_once __DIR__ . '/../ManyToMany.php';
|
||||
require_once __DIR__ . '/../Table.php';
|
||||
require_once __DIR__ . '/../UniqueConstraint.php';
|
||||
require_once __DIR__ . '/../Index.php';
|
||||
require_once __DIR__ . '/../JoinTable.php';
|
||||
require_once __DIR__ . '/../SequenceGenerator.php';
|
||||
require_once __DIR__ . '/../CustomIdGenerator.php';
|
||||
require_once __DIR__ . '/../ChangeTrackingPolicy.php';
|
||||
require_once __DIR__ . '/../OrderBy.php';
|
||||
require_once __DIR__ . '/../NamedQueries.php';
|
||||
require_once __DIR__ . '/../NamedQuery.php';
|
||||
require_once __DIR__ . '/../HasLifecycleCallbacks.php';
|
||||
require_once __DIR__ . '/../PrePersist.php';
|
||||
require_once __DIR__ . '/../PostPersist.php';
|
||||
require_once __DIR__ . '/../PreUpdate.php';
|
||||
require_once __DIR__ . '/../PostUpdate.php';
|
||||
require_once __DIR__ . '/../PreRemove.php';
|
||||
require_once __DIR__ . '/../PostRemove.php';
|
||||
require_once __DIR__ . '/../PostLoad.php';
|
||||
require_once __DIR__ . '/../PreFlush.php';
|
||||
require_once __DIR__ . '/../FieldResult.php';
|
||||
require_once __DIR__ . '/../ColumnResult.php';
|
||||
require_once __DIR__ . '/../EntityResult.php';
|
||||
require_once __DIR__ . '/../NamedNativeQuery.php';
|
||||
require_once __DIR__ . '/../NamedNativeQueries.php';
|
||||
require_once __DIR__ . '/../SqlResultSetMapping.php';
|
||||
require_once __DIR__ . '/../SqlResultSetMappings.php';
|
||||
require_once __DIR__ . '/../AssociationOverride.php';
|
||||
require_once __DIR__ . '/../AssociationOverrides.php';
|
||||
require_once __DIR__ . '/../AttributeOverride.php';
|
||||
require_once __DIR__ . '/../AttributeOverrides.php';
|
||||
require_once __DIR__ . '/../EntityListeners.php';
|
||||
require_once __DIR__ . '/../Cache.php';
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use Attribute;
|
||||
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
final class InheritanceType implements Annotation
|
||||
{
|
||||
/**
|
||||
* The inheritance type used by the class and its subclasses.
|
||||
*
|
||||
* @var string
|
||||
* @Enum({"NONE", "JOINED", "SINGLE_TABLE", "TABLE_PER_CLASS"})
|
||||
*/
|
||||
public $value;
|
||||
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use Attribute;
|
||||
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target({"PROPERTY","ANNOTATION"})
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
|
||||
final class JoinColumn implements Annotation
|
||||
{
|
||||
/** @var string|null */
|
||||
public $name;
|
||||
|
||||
/** @var string */
|
||||
public $referencedColumnName = 'id';
|
||||
|
||||
/** @var bool */
|
||||
public $unique = false;
|
||||
|
||||
/** @var bool */
|
||||
public $nullable = true;
|
||||
|
||||
/** @var mixed */
|
||||
public $onDelete;
|
||||
|
||||
/** @var string|null */
|
||||
public $columnDefinition;
|
||||
|
||||
/**
|
||||
* Field name used in non-object hydration (array/scalar).
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public $fieldName;
|
||||
|
||||
/** @var array<string, mixed> */
|
||||
public $options = [];
|
||||
|
||||
/** @param array<string, mixed> $options */
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
string $referencedColumnName = 'id',
|
||||
bool $unique = false,
|
||||
bool $nullable = true,
|
||||
$onDelete = null,
|
||||
?string $columnDefinition = null,
|
||||
?string $fieldName = null,
|
||||
array $options = []
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->referencedColumnName = $referencedColumnName;
|
||||
$this->unique = $unique;
|
||||
$this->nullable = $nullable;
|
||||
$this->onDelete = $onDelete;
|
||||
$this->columnDefinition = $columnDefinition;
|
||||
$this->fieldName = $fieldName;
|
||||
$this->options = $options;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Proxy;
|
||||
|
||||
use Doctrine\Common\Proxy\Proxy as BaseProxy;
|
||||
|
||||
/**
|
||||
* Interface for proxy classes.
|
||||
*/
|
||||
interface Proxy extends BaseProxy
|
||||
{
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Proxy;
|
||||
|
||||
use Closure;
|
||||
use Doctrine\Common\Proxy\AbstractProxyFactory;
|
||||
use Doctrine\Common\Proxy\Proxy as BaseProxy;
|
||||
use Doctrine\Common\Proxy\ProxyDefinition;
|
||||
use Doctrine\Common\Proxy\ProxyGenerator;
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityNotFoundException;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\ORM\Utility\IdentifierFlattener;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* This factory is used to create proxy objects for entities at runtime.
|
||||
*
|
||||
* @psalm-type AutogenerateMode = AbstractProxyFactory::AUTOGENERATE_NEVER|AbstractProxyFactory::AUTOGENERATE_ALWAYS|AbstractProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS|AbstractProxyFactory::AUTOGENERATE_EVAL|AbstractProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED
|
||||
*/
|
||||
class ProxyFactory extends AbstractProxyFactory
|
||||
{
|
||||
/** @var EntityManagerInterface The EntityManager this factory is bound to. */
|
||||
private $em;
|
||||
|
||||
/** @var UnitOfWork The UnitOfWork this factory uses to retrieve persisters */
|
||||
private $uow;
|
||||
|
||||
/** @var string */
|
||||
private $proxyNs;
|
||||
|
||||
/**
|
||||
* The IdentifierFlattener used for manipulating identifiers
|
||||
*
|
||||
* @var IdentifierFlattener
|
||||
*/
|
||||
private $identifierFlattener;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the <tt>ProxyFactory</tt> class that is
|
||||
* connected to the given <tt>EntityManager</tt>.
|
||||
*
|
||||
* @param EntityManagerInterface $em The EntityManager the new factory works for.
|
||||
* @param string $proxyDir The directory to use for the proxy classes. It must exist.
|
||||
* @param string $proxyNs The namespace to use for the proxy classes.
|
||||
* @param bool|int $autoGenerate The strategy for automatically generating proxy classes. Possible
|
||||
* values are constants of {@see AbstractProxyFactory}.
|
||||
* @psalm-param bool|AutogenerateMode $autoGenerate
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em, $proxyDir, $proxyNs, $autoGenerate = AbstractProxyFactory::AUTOGENERATE_NEVER)
|
||||
{
|
||||
$proxyGenerator = new ProxyGenerator($proxyDir, $proxyNs);
|
||||
|
||||
$proxyGenerator->setPlaceholder('baseProxyInterface', Proxy::class);
|
||||
|
||||
parent::__construct($proxyGenerator, $em->getMetadataFactory(), $autoGenerate);
|
||||
|
||||
$this->em = $em;
|
||||
$this->uow = $em->getUnitOfWork();
|
||||
$this->proxyNs = $proxyNs;
|
||||
$this->identifierFlattener = new IdentifierFlattener($this->uow, $em->getMetadataFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function skipClass(ClassMetadata $metadata)
|
||||
{
|
||||
return $metadata->isMappedSuperclass
|
||||
|| $metadata->isEmbeddedClass
|
||||
|| $metadata->getReflectionClass()->isAbstract();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function createProxyDefinition($className)
|
||||
{
|
||||
$classMetadata = $this->em->getClassMetadata($className);
|
||||
$entityPersister = $this->uow->getEntityPersister($className);
|
||||
|
||||
return new ProxyDefinition(
|
||||
ClassUtils::generateProxyClassName($className, $this->proxyNs),
|
||||
$classMetadata->getIdentifierFieldNames(),
|
||||
$classMetadata->getReflectionProperties(),
|
||||
$this->createInitializer($classMetadata, $entityPersister),
|
||||
$this->createCloner($classMetadata, $entityPersister)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a closure capable of initializing a proxy
|
||||
*
|
||||
* @psalm-return Closure(BaseProxy):void
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
*/
|
||||
private function createInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister): Closure
|
||||
{
|
||||
$wakeupProxy = $classMetadata->getReflectionClass()->hasMethod('__wakeup');
|
||||
|
||||
return function (BaseProxy $proxy) use ($entityPersister, $classMetadata, $wakeupProxy): void {
|
||||
$initializer = $proxy->__getInitializer();
|
||||
$cloner = $proxy->__getCloner();
|
||||
|
||||
$proxy->__setInitializer(null);
|
||||
$proxy->__setCloner(null);
|
||||
|
||||
if ($proxy->__isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$properties = $proxy->__getLazyProperties();
|
||||
|
||||
foreach ($properties as $propertyName => $property) {
|
||||
if (! isset($proxy->$propertyName)) {
|
||||
$proxy->$propertyName = $properties[$propertyName];
|
||||
}
|
||||
}
|
||||
|
||||
$proxy->__setInitialized(true);
|
||||
|
||||
if ($wakeupProxy) {
|
||||
$proxy->__wakeup();
|
||||
}
|
||||
|
||||
$identifier = $classMetadata->getIdentifierValues($proxy);
|
||||
|
||||
if ($entityPersister->loadById($identifier, $proxy) === null) {
|
||||
$proxy->__setInitializer($initializer);
|
||||
$proxy->__setCloner($cloner);
|
||||
$proxy->__setInitialized(false);
|
||||
|
||||
throw EntityNotFoundException::fromClassNameAndIdentifier(
|
||||
$classMetadata->getName(),
|
||||
$this->identifierFlattener->flattenIdentifier($classMetadata, $identifier)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a closure capable of finalizing state a cloned proxy
|
||||
*
|
||||
* @psalm-return Closure(BaseProxy):void
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
*/
|
||||
private function createCloner(ClassMetadata $classMetadata, EntityPersister $entityPersister): Closure
|
||||
{
|
||||
return function (BaseProxy $proxy) use ($entityPersister, $classMetadata): void {
|
||||
if ($proxy->__isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$proxy->__setInitialized(true);
|
||||
$proxy->__setInitializer(null);
|
||||
|
||||
$class = $entityPersister->getClassMetadata();
|
||||
$identifier = $classMetadata->getIdentifierValues($proxy);
|
||||
$original = $entityPersister->loadById($identifier);
|
||||
|
||||
if ($original === null) {
|
||||
throw EntityNotFoundException::fromClassNameAndIdentifier(
|
||||
$classMetadata->getName(),
|
||||
$this->identifierFlattener->flattenIdentifier($classMetadata, $identifier)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($class->getReflectionProperties() as $property) {
|
||||
if (! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($proxy, $property->getValue($original));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")")
|
||||
* InstanceOfParameter ::= AbstractSchemaName | InputParameter
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*/
|
||||
class InstanceOfExpression extends Node
|
||||
{
|
||||
/** @var bool */
|
||||
public $not;
|
||||
|
||||
/** @var string */
|
||||
public $identificationVariable;
|
||||
|
||||
/** @var mixed[] */
|
||||
public $value;
|
||||
|
||||
/** @param string $identVariable */
|
||||
public function __construct($identVariable)
|
||||
{
|
||||
$this->identificationVariable = $identVariable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dispatch($sqlWalker)
|
||||
{
|
||||
return $sqlWalker->walkInstanceOfExpression($this);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\Exec;
|
||||
|
||||
use Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Result;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
|
||||
/**
|
||||
* Base class for SQL statement executors.
|
||||
*
|
||||
* @link http://www.doctrine-project.org
|
||||
*
|
||||
* @todo Rename: AbstractSQLExecutor
|
||||
*/
|
||||
abstract class AbstractSqlExecutor
|
||||
{
|
||||
/** @var list<string>|string */
|
||||
protected $_sqlStatements;
|
||||
|
||||
/** @var QueryCacheProfile */
|
||||
protected $queryCacheProfile;
|
||||
|
||||
/**
|
||||
* Gets the SQL statements that are executed by the executor.
|
||||
*
|
||||
* @return mixed[]|string All the SQL update statements.
|
||||
*/
|
||||
public function getSqlStatements()
|
||||
{
|
||||
return $this->_sqlStatements;
|
||||
}
|
||||
|
||||
/** @return void */
|
||||
public function setQueryCacheProfile(QueryCacheProfile $qcp)
|
||||
{
|
||||
$this->queryCacheProfile = $qcp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not use query cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function removeQueryCacheProfile()
|
||||
{
|
||||
$this->queryCacheProfile = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all sql statements.
|
||||
*
|
||||
* @param Connection $conn The database connection that is used to execute the queries.
|
||||
* @psalm-param array<int, mixed>|array<string, mixed> $params The parameters.
|
||||
* @psalm-param array<int, int|string|Type|null>|
|
||||
* array<string, int|string|Type|null> $types The parameter types.
|
||||
*
|
||||
* @return Result|int
|
||||
*/
|
||||
abstract public function execute(Connection $conn, array $params, array $types);
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
use Doctrine\Common\Lexer\AbstractLexer;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
use function constant;
|
||||
use function ctype_alpha;
|
||||
use function defined;
|
||||
use function is_numeric;
|
||||
use function str_contains;
|
||||
use function str_replace;
|
||||
use function stripos;
|
||||
use function strlen;
|
||||
use function strtoupper;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* Scans a DQL query for tokens.
|
||||
*/
|
||||
class Lexer extends AbstractLexer
|
||||
{
|
||||
// All tokens that are not valid identifiers must be < 100
|
||||
public const T_NONE = 1;
|
||||
public const T_INTEGER = 2;
|
||||
public const T_STRING = 3;
|
||||
public const T_INPUT_PARAMETER = 4;
|
||||
public const T_FLOAT = 5;
|
||||
public const T_CLOSE_PARENTHESIS = 6;
|
||||
public const T_OPEN_PARENTHESIS = 7;
|
||||
public const T_COMMA = 8;
|
||||
public const T_DIVIDE = 9;
|
||||
public const T_DOT = 10;
|
||||
public const T_EQUALS = 11;
|
||||
public const T_GREATER_THAN = 12;
|
||||
public const T_LOWER_THAN = 13;
|
||||
public const T_MINUS = 14;
|
||||
public const T_MULTIPLY = 15;
|
||||
public const T_NEGATE = 16;
|
||||
public const T_PLUS = 17;
|
||||
public const T_OPEN_CURLY_BRACE = 18;
|
||||
public const T_CLOSE_CURLY_BRACE = 19;
|
||||
|
||||
// All tokens that are identifiers or keywords that could be considered as identifiers should be >= 100
|
||||
/** @deprecated No Replacement planned. */
|
||||
public const T_ALIASED_NAME = 100;
|
||||
public const T_FULLY_QUALIFIED_NAME = 101;
|
||||
public const T_IDENTIFIER = 102;
|
||||
|
||||
// All keyword tokens should be >= 200
|
||||
public const T_ALL = 200;
|
||||
public const T_AND = 201;
|
||||
public const T_ANY = 202;
|
||||
public const T_AS = 203;
|
||||
public const T_ASC = 204;
|
||||
public const T_AVG = 205;
|
||||
public const T_BETWEEN = 206;
|
||||
public const T_BOTH = 207;
|
||||
public const T_BY = 208;
|
||||
public const T_CASE = 209;
|
||||
public const T_COALESCE = 210;
|
||||
public const T_COUNT = 211;
|
||||
public const T_DELETE = 212;
|
||||
public const T_DESC = 213;
|
||||
public const T_DISTINCT = 214;
|
||||
public const T_ELSE = 215;
|
||||
public const T_EMPTY = 216;
|
||||
public const T_END = 217;
|
||||
public const T_ESCAPE = 218;
|
||||
public const T_EXISTS = 219;
|
||||
public const T_FALSE = 220;
|
||||
public const T_FROM = 221;
|
||||
public const T_GROUP = 222;
|
||||
public const T_HAVING = 223;
|
||||
public const T_HIDDEN = 224;
|
||||
public const T_IN = 225;
|
||||
public const T_INDEX = 226;
|
||||
public const T_INNER = 227;
|
||||
public const T_INSTANCE = 228;
|
||||
public const T_IS = 229;
|
||||
public const T_JOIN = 230;
|
||||
public const T_LEADING = 231;
|
||||
public const T_LEFT = 232;
|
||||
public const T_LIKE = 233;
|
||||
public const T_MAX = 234;
|
||||
public const T_MEMBER = 235;
|
||||
public const T_MIN = 236;
|
||||
public const T_NEW = 237;
|
||||
public const T_NOT = 238;
|
||||
public const T_NULL = 239;
|
||||
public const T_NULLIF = 240;
|
||||
public const T_OF = 241;
|
||||
public const T_OR = 242;
|
||||
public const T_ORDER = 243;
|
||||
public const T_OUTER = 244;
|
||||
public const T_PARTIAL = 245;
|
||||
public const T_SELECT = 246;
|
||||
public const T_SET = 247;
|
||||
public const T_SOME = 248;
|
||||
public const T_SUM = 249;
|
||||
public const T_THEN = 250;
|
||||
public const T_TRAILING = 251;
|
||||
public const T_TRUE = 252;
|
||||
public const T_UPDATE = 253;
|
||||
public const T_WHEN = 254;
|
||||
public const T_WHERE = 255;
|
||||
public const T_WITH = 256;
|
||||
|
||||
/**
|
||||
* Creates a new query scanner object.
|
||||
*
|
||||
* @param string $input A query string.
|
||||
*/
|
||||
public function __construct($input)
|
||||
{
|
||||
$this->setInput($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCatchablePatterns()
|
||||
{
|
||||
return [
|
||||
'[a-z_][a-z0-9_]*\:[a-z_][a-z0-9_]*(?:\\\[a-z_][a-z0-9_]*)*', // aliased name
|
||||
'[a-z_\\\][a-z0-9_]*(?:\\\[a-z_][a-z0-9_]*)*', // identifier or qualified name
|
||||
'(?:[0-9]+(?:[\.][0-9]+)*)(?:e[+-]?[0-9]+)?', // numbers
|
||||
"'(?:[^']|'')*'", // quoted strings
|
||||
'\?[0-9]*|:[a-z_][a-z0-9_]*', // parameters
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNonCatchablePatterns()
|
||||
{
|
||||
return ['\s+', '--.*', '(.)'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getType(&$value)
|
||||
{
|
||||
$type = self::T_NONE;
|
||||
|
||||
switch (true) {
|
||||
// Recognize numeric values
|
||||
case is_numeric($value):
|
||||
if (str_contains($value, '.') || stripos($value, 'e') !== false) {
|
||||
return self::T_FLOAT;
|
||||
}
|
||||
|
||||
return self::T_INTEGER;
|
||||
|
||||
// Recognize quoted strings
|
||||
case $value[0] === "'":
|
||||
$value = str_replace("''", "'", substr($value, 1, strlen($value) - 2));
|
||||
|
||||
return self::T_STRING;
|
||||
|
||||
// Recognize identifiers, aliased or qualified names
|
||||
case ctype_alpha($value[0]) || $value[0] === '_' || $value[0] === '\\':
|
||||
$name = 'Doctrine\ORM\Query\Lexer::T_' . strtoupper($value);
|
||||
|
||||
if (defined($name)) {
|
||||
$type = constant($name);
|
||||
|
||||
if ($type > 100) {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
||||
if (str_contains($value, ':')) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/8818',
|
||||
'Short namespace aliases such as "%s" are deprecated and will be removed in Doctrine ORM 3.0.',
|
||||
$value
|
||||
);
|
||||
|
||||
return self::T_ALIASED_NAME;
|
||||
}
|
||||
|
||||
if (str_contains($value, '\\')) {
|
||||
return self::T_FULLY_QUALIFIED_NAME;
|
||||
}
|
||||
|
||||
return self::T_IDENTIFIER;
|
||||
|
||||
// Recognize input parameters
|
||||
case $value[0] === '?' || $value[0] === ':':
|
||||
return self::T_INPUT_PARAMETER;
|
||||
|
||||
// Recognize symbols
|
||||
case $value === '.':
|
||||
return self::T_DOT;
|
||||
|
||||
case $value === ',':
|
||||
return self::T_COMMA;
|
||||
|
||||
case $value === '(':
|
||||
return self::T_OPEN_PARENTHESIS;
|
||||
|
||||
case $value === ')':
|
||||
return self::T_CLOSE_PARENTHESIS;
|
||||
|
||||
case $value === '=':
|
||||
return self::T_EQUALS;
|
||||
|
||||
case $value === '>':
|
||||
return self::T_GREATER_THAN;
|
||||
|
||||
case $value === '<':
|
||||
return self::T_LOWER_THAN;
|
||||
|
||||
case $value === '+':
|
||||
return self::T_PLUS;
|
||||
|
||||
case $value === '-':
|
||||
return self::T_MINUS;
|
||||
|
||||
case $value === '*':
|
||||
return self::T_MULTIPLY;
|
||||
|
||||
case $value === '/':
|
||||
return self::T_DIVIDE;
|
||||
|
||||
case $value === '!':
|
||||
return self::T_NEGATE;
|
||||
|
||||
case $value === '{':
|
||||
return self::T_OPEN_CURLY_BRACE;
|
||||
|
||||
case $value === '}':
|
||||
return self::T_CLOSE_CURLY_BRACE;
|
||||
|
||||
// Default
|
||||
default:
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
|
||||
|
||||
/**
|
||||
* Encapsulates the resulting components from a DQL query parsing process that
|
||||
* can be serialized.
|
||||
*
|
||||
* @link http://www.doctrine-project.org
|
||||
*/
|
||||
class ParserResult
|
||||
{
|
||||
/**
|
||||
* The SQL executor used for executing the SQL.
|
||||
*
|
||||
* @var AbstractSqlExecutor
|
||||
*/
|
||||
private $_sqlExecutor;
|
||||
|
||||
/**
|
||||
* The ResultSetMapping that describes how to map the SQL result set.
|
||||
*
|
||||
* @var ResultSetMapping
|
||||
*/
|
||||
private $_resultSetMapping;
|
||||
|
||||
/**
|
||||
* The mappings of DQL parameter names/positions to SQL parameter positions.
|
||||
*
|
||||
* @psalm-var array<string|int, list<int>>
|
||||
*/
|
||||
private $_parameterMappings = [];
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the <tt>ParserResult</tt> class.
|
||||
* The new instance is initialized with an empty <tt>ResultSetMapping</tt>.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_resultSetMapping = new ResultSetMapping();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ResultSetMapping for the parsed query.
|
||||
*
|
||||
* @return ResultSetMapping The result set mapping of the parsed query
|
||||
*/
|
||||
public function getResultSetMapping()
|
||||
{
|
||||
return $this->_resultSetMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ResultSetMapping of the parsed query.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setResultSetMapping(ResultSetMapping $rsm)
|
||||
{
|
||||
$this->_resultSetMapping = $rsm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SQL executor that should be used for this ParserResult.
|
||||
*
|
||||
* @param AbstractSqlExecutor $executor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setSqlExecutor($executor)
|
||||
{
|
||||
$this->_sqlExecutor = $executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL executor used by this ParserResult.
|
||||
*
|
||||
* @return AbstractSqlExecutor
|
||||
*/
|
||||
public function getSqlExecutor()
|
||||
{
|
||||
return $this->_sqlExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a DQL to SQL parameter mapping. One DQL parameter name/position can map to
|
||||
* several SQL parameter positions.
|
||||
*
|
||||
* @param string|int $dqlPosition
|
||||
* @param int $sqlPosition
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addParameterMapping($dqlPosition, $sqlPosition)
|
||||
{
|
||||
$this->_parameterMappings[$dqlPosition][] = $sqlPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all DQL to SQL parameter mappings.
|
||||
*
|
||||
* @psalm-return array<int|string, list<int>> The parameter mappings.
|
||||
*/
|
||||
public function getParameterMappings()
|
||||
{
|
||||
return $this->_parameterMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL parameter positions for a DQL parameter name/position.
|
||||
*
|
||||
* @param string|int $dqlPosition The name or position of the DQL parameter.
|
||||
*
|
||||
* @return int[] The positions of the corresponding SQL parameters.
|
||||
* @psalm-return list<int>
|
||||
*/
|
||||
public function getSqlParameterPositions($dqlPosition)
|
||||
{
|
||||
return $this->_parameterMappings[$dqlPosition];
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"runner.bootstrap": "tests/Doctrine/Tests/TestInit.php",
|
||||
"runner.path": "tests/Doctrine/Performance",
|
||||
"runner.bootstrap": "tests/Tests/TestInit.php",
|
||||
"runner.path": "tests/Performance",
|
||||
"runner.file_pattern": "*Bench.php",
|
||||
|
||||
"core.extensions": [
|
||||
|
||||
264
phpcs.xml.dist
264
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"/>
|
||||
@@ -11,12 +13,11 @@
|
||||
|
||||
<config name="php_version" value="70100"/>
|
||||
|
||||
<file>lib</file>
|
||||
<file>src</file>
|
||||
<file>tests</file>
|
||||
|
||||
<exclude-pattern>*/lib/Doctrine/ORM/Mapping/InverseJoinColumn.php</exclude-pattern>
|
||||
<exclude-pattern>*/tests/Doctrine/Tests/Proxies/__CG__*</exclude-pattern>
|
||||
<exclude-pattern>*/tests/Doctrine/Tests/ORM/Tools/Export/export/*</exclude-pattern>
|
||||
<exclude-pattern>*/tests/Tests/Proxies/__CG__*</exclude-pattern>
|
||||
<exclude-pattern>*/tests/Tests/ORM/Tools/Export/export/*</exclude-pattern>
|
||||
|
||||
<rule ref="Doctrine">
|
||||
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint" />
|
||||
@@ -34,111 +35,119 @@
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint">
|
||||
<exclude-pattern>*/lib/*</exclude-pattern>
|
||||
<exclude-pattern>*/src/*</exclude-pattern>
|
||||
<!--
|
||||
that class extends another one inside lib/ and can therefore not
|
||||
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/Doctrine/Tests/Mocks/HydratorMockStatement.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Mocks/HydratorMockStatement.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint">
|
||||
<exclude-pattern>*/lib/*</exclude-pattern>
|
||||
<exclude-pattern>*/src/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="PSR1.Classes.ClassDeclaration.MultipleClasses">
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Driver/CompatibilityAnnotationDriver.php</exclude-pattern>
|
||||
<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>tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.Classes.ClassFileName.NoMatch">
|
||||
<exclude-pattern>*/tests/*</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/Console/Helper/EntityManagerHelper.php</exclude-pattern>
|
||||
<exclude-pattern>tests/*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps">
|
||||
<exclude-pattern>src/Tools/Debug.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Tools/DebugTest.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase">
|
||||
<exclude-pattern>lib/Doctrine/ORM/Events.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/ToolEvents.php</exclude-pattern>
|
||||
<exclude-pattern>src/Events.php</exclude-pattern>
|
||||
<exclude-pattern>src/Tools/ToolEvents.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingTraversableTypeHintSpecification">
|
||||
<!-- https://github.com/doctrine/annotations/issues/129 -->
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Column.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Index.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Table.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/UniqueConstraint.php</exclude-pattern>
|
||||
<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>lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php</exclude-pattern>
|
||||
<exclude-pattern>src/Internal/Hydration/AbstractHydrator.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
|
||||
<exclude-pattern>lib/Doctrine/ORM/Query/Parser.php</exclude-pattern>
|
||||
<exclude-pattern>src/Query/Parser.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFullyQualifiedName">
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/AssociationOverride.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/AssociationOverrides.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/AttributeOverride.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/AttributeOverrides.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Cache.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/ChangeTrackingPolicy.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Column.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/ColumnResult.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/CustomIdGenerator.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/DiscriminatorColumn.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/DiscriminatorMap.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Embeddable.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Embedded.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Entity.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/EntityListeners.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/EntityResult.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/FieldResult.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/GeneratedValue.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/HasLifecycleCallbacks.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Id.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Index.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/InheritanceType.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/JoinColumn.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/JoinColumns.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/JoinTable.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/ManyToMany.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/ManyToOne.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/MappedSuperclass.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/NamedNativeQueries.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/NamedNativeQuery.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/NamedQueries.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/NamedQuery.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/OneToMany.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/OneToOne.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/OrderBy.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/PostLoad.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/PostPersist.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/PostRemove.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/PostUpdate.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/PreFlush.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/PrePersist.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/PreRemove.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/PreUpdate.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/SequenceGenerator.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/SqlResultSetMapping.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/SqlResultSetMappings.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Table.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/UniqueConstraint.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/Version.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/AssociationOverride.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/AssociationOverrides.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/AttributeOverride.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/AttributeOverrides.php</exclude-pattern>
|
||||
<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>
|
||||
<exclude-pattern>src/Mapping/Embeddable.php</exclude-pattern>
|
||||
<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>
|
||||
<exclude-pattern>src/Mapping/Index.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/InheritanceType.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/JoinColumn.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/JoinColumns.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/JoinTable.php</exclude-pattern>
|
||||
<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>
|
||||
<exclude-pattern>src/Mapping/PostLoad.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/PostPersist.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/PostRemove.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/PostUpdate.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/PreFlush.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/PrePersist.php</exclude-pattern>
|
||||
<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>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Commenting.EmptyComment">
|
||||
<exclude-pattern>lib/Doctrine/ORM/Cache/DefaultQueryCache.php</exclude-pattern>
|
||||
<exclude-pattern>src/Cache/DefaultQueryCache.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Classes.SuperfluousInterfaceNaming">
|
||||
<exclude-pattern>lib/Doctrine/ORM/EntityManagerInterface.php</exclude-pattern>
|
||||
<exclude-pattern>src/EntityManagerInterface.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Classes.SuperfluousTraitNaming.SuperfluousSuffix">
|
||||
<exclude-pattern>tests/Doctrine/Tests/Models/DDC1872/DDC1872ExampleTrait.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Models/DDC1872/DDC1872ExampleTrait.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint">
|
||||
@@ -159,25 +168,25 @@
|
||||
|
||||
<!-- intentionally without namespace -->
|
||||
<rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
|
||||
<exclude-pattern>tests/Doctrine/Tests/Models/Global/GlobalNamespaceModel.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/Models/DDC3231/DDC3231User1NoNamespace.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/Models/DDC3231/DDC3231User2NoNamespace.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Models/Global/GlobalNamespaceModel.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Models/DDC3231/DDC3231User1NoNamespace.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Models/DDC3231/DDC3231User2NoNamespace.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<!-- file with multiple namespaces confuses the sniff -->
|
||||
<rule ref="PSR2.Namespaces.UseDeclaration.UseAfterNamespace">
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2084Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC2084Test.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<!-- file with multiple namespaces confuses the sniff -->
|
||||
<rule ref="SlevomatCodingStandard.Namespaces.AlphabeticallySortedUses.IncorrectlyOrderedUses">
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2084Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC2084Test.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<!-- intentionally empty blocks -->
|
||||
<rule ref="Generic.CodeAnalysis.EmptyStatement.DetectedForeach">
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1301Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC1301Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/ExtraLazyCollectionTest.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<!--
|
||||
@@ -185,90 +194,95 @@
|
||||
different namespace. The use statement has to stay.
|
||||
-->
|
||||
<rule ref="SlevomatCodingStandard.Namespaces.UseFromSameNamespace.UseFromSameNamespace">
|
||||
<exclude-pattern>tests/Doctrine/Tests/Models/DDC1590/DDC1590User.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Models/DDC1590/DDC1590User.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Commenting.ForbiddenAnnotations.AnnotationForbidden">
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/Ticket/DDC832Test.php</exclude-pattern>
|
||||
<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 -->
|
||||
<exclude-pattern>tests/Tests/Proxy/DefaultProxyClassNameResolverTest.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.Commenting.FunctionComment.WrongStyle">
|
||||
<!-- https://github.com/squizlabs/PHP_CodeSniffer/issues/1961 -->
|
||||
<exclude-pattern>tests/Doctrine/Tests/Mocks/DatabasePlatformMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/Mocks/DriverMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/UnitOfWorkTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Query/DeleteSqlGenerationTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Mocks/DatabasePlatformMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Mocks/DriverMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/UnitOfWorkTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Query/DeleteSqlGenerationTest.php</exclude-pattern>
|
||||
</rule>
|
||||
<rule ref="Squiz.Commenting.FunctionComment.InvalidNoReturn">
|
||||
<!-- https://github.com/squizlabs/PHP_CodeSniffer/issues/2099 -->
|
||||
<exclude-pattern>lib/Doctrine/ORM/Query/AST/Node.php</exclude-pattern>
|
||||
<exclude-pattern>src/Query/AST/Node.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.NoAssignment">
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests*</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Mapping/php/Doctrine.Tests*</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="PSR2.Methods.MethodDeclaration.Underscore">
|
||||
<exclude-pattern>lib/Doctrine/ORM/AbstractQuery.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/NativeQuery.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Query.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Query/TreeWalkerAdapter.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php</exclude-pattern>
|
||||
<exclude-pattern>src/AbstractQuery.php</exclude-pattern>
|
||||
<exclude-pattern>src/Mapping/ClassMetadataInfo.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/Doctrine/Tests/Mocks/DatabasePlatformMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/Mocks/SchemaManagerMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/Ticket/DDC3634Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Mocks/DatabasePlatformMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/Mocks/SchemaManagerMock.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC3634Test.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.NamingConventions.ValidVariableName.PublicHasUnderscore">
|
||||
<exclude-pattern>lib/Doctrine/ORM/AbstractQuery.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Configuration.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/EntityRepository.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Query/Printer.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/EntityRepositoryGenerator.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/Console/Helper/EntityManagerHelper.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/Export/Driver/AbstractExporter.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/Export/Driver/AnnotationExporter.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php</exclude-pattern>
|
||||
<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/Doctrine/Tests/OrmFunctionalTestCase.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/OrmFunctionalTestCase.php</exclude-pattern>
|
||||
</rule>
|
||||
<rule ref="Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps">
|
||||
<!-- Member variable "__isCloning" is not in valid camel caps format -->
|
||||
<exclude-pattern>src/Proxy/ProxyFactory.php</exclude-pattern>
|
||||
<!-- accessing public property __isInitialized__ of a proxy -->
|
||||
<exclude-pattern>lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php</exclude-pattern>
|
||||
<exclude-pattern>lib/Doctrine/ORM/UnitOfWork.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/DefaultValuesTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/OneToManyBidirectionalAssociationTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/ProxiesLikeEntitiesTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2231Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/ProxiesLikeEntitiesTest.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Namespaces.UnusedUses.MismatchingCaseSensitivity">
|
||||
<!-- Using @group and Group entity in the same file -->
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1885Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1843Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC1885Test.php</exclude-pattern>
|
||||
<exclude-pattern>tests/Tests/ORM/Functional/Ticket/DDC1843Test.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="Generic.CodeAnalysis.EmptyStatement.DetectedElse">
|
||||
<!-- The missing code needs to be implemented someday -->
|
||||
<exclude-pattern>lib/Doctrine/ORM/Id/TableGenerator.php</exclude-pattern>
|
||||
<exclude-pattern>src/Id/TableGenerator.php</exclude-pattern>
|
||||
</rule>
|
||||
<rule ref="Generic.CodeAnalysis.EmptyStatement.DetectedIf">
|
||||
<!-- The missing code needs to be implemented someday -->
|
||||
<exclude-pattern>lib/Doctrine/ORM/Id/TableGenerator.php</exclude-pattern>
|
||||
<exclude-pattern>src/Id/TableGenerator.php</exclude-pattern>
|
||||
</rule>
|
||||
<rule ref="Squiz.Commenting.FunctionComment.ExtraParamComment">
|
||||
<!-- https://github.com/doctrine/orm/issues/8537 -->
|
||||
<exclude-pattern>lib/Doctrine/ORM/QueryBuilder.php</exclude-pattern>
|
||||
<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
@@ -7,46 +7,88 @@ parameters:
|
||||
|
||||
ignoreErrors:
|
||||
# PHPStan doesn't understand our method_exists() safeguards.
|
||||
- '/Call to function method_exists.*/'
|
||||
- '/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: lib/Doctrine/ORM/Configuration.php
|
||||
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: lib/Doctrine/ORM/AbstractQuery.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: lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php
|
||||
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: lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php
|
||||
path: src/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
# False positive
|
||||
-
|
||||
message: '/^Call to an undefined method Doctrine\\Common\\Cache\\Cache::deleteAll\(\)\.$/'
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Tools/Console/Command/ClearCache/ResultCommand.php
|
||||
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: lib/Doctrine/ORM/Query/AST/Functions/LocateFunction.php
|
||||
path: src/Query/AST/Functions/LocateFunction.php
|
||||
|
||||
# Won't get fixed in DBAL 2
|
||||
-
|
||||
message: '#.*deleteItem.*expects string.*#'
|
||||
count: 1
|
||||
path: src/Query.php
|
||||
|
||||
-
|
||||
message: '#.*get(Drop|Create)SchemaS(ql|QL).*should return list.*but returns array.*#'
|
||||
count: 2
|
||||
path: src/Tools/SchemaTool.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$start of method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getSubstringExpression\\(\\) expects int, string given\\.$#"
|
||||
count: 1
|
||||
path: lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php
|
||||
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: lib/Doctrine/ORM/Query/AST/Functions/SubstringFunction.php
|
||||
path: src/Query/AST/Functions/SubstringFunction.php
|
||||
|
||||
-
|
||||
message: '#^Class Doctrine\\DBAL\\Platforms\\MySQLPlatform not found\.$#'
|
||||
count: 2
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
- '~^Call to deprecated method getSQLResultCasing\(\) of class Doctrine\\DBAL\\Platforms\\AbstractPlatform\.$~'
|
||||
-
|
||||
message: '~deprecated class Doctrine\\DBAL\\Tools\\Console\\Command\\ImportCommand\:~'
|
||||
path: src/Tools/Console/ConsoleRunner.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\AbstractQuery\:\:getHydrationCacheId\(\) should return array\{string, string\} but returns array\<string\>\.$#'
|
||||
path: src/AbstractQuery.php
|
||||
|
||||
-
|
||||
message: '#^Method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:\w+\(\) has parameter \$stmt with no value type specified in iterable type Doctrine\\DBAL\\Driver\\ResultStatement\.$#'
|
||||
path: src/Internal/Hydration/AbstractHydrator.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$key of method Psr\\Cache\\CacheItemPoolInterface\:\:deleteItem\(\) expects string, string\|false given\.$#'
|
||||
path: src/Query
|
||||
|
||||
|
||||
# Symfony cache supports passing a key prefix to the clear method.
|
||||
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
|
||||
@@ -54,10 +96,16 @@ parameters:
|
||||
# Persistence 2 support
|
||||
-
|
||||
message: '/clear.*invoked with 1 parameter/'
|
||||
path: lib/Doctrine/ORM/EntityRepository.php
|
||||
path: src/EntityRepository.php
|
||||
-
|
||||
message: '#^Class Doctrine\\Persistence\\ObjectManagerAware not found\.$#'
|
||||
path: lib/Doctrine/ORM/UnitOfWork.php
|
||||
path: src/UnitOfWork.php
|
||||
-
|
||||
message: '#^Call to method injectObjectManager\(\) on an unknown class Doctrine\\Persistence\\ObjectManagerAware\.$#'
|
||||
path: lib/Doctrine/ORM/UnitOfWork.php
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '#contains generic type.*but class.*is not generic#'
|
||||
paths:
|
||||
- src/Mapping/Driver/XmlDriver.php
|
||||
- src/Mapping/Driver/YamlDriver.php
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user