mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
607 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8291a7f09b | ||
|
|
26e274e373 | ||
|
|
5209184a60 | ||
|
|
23f54885bc | ||
|
|
7f29b576d8 | ||
|
|
a8425a5248 | ||
|
|
86ce0e5e35 | ||
|
|
39fd5f4d46 | ||
|
|
a9309d748b | ||
|
|
fe09af6df1 | ||
|
|
ed50e3d967 | ||
|
|
1d59e46245 | ||
|
|
a0a0b0e476 | ||
|
|
0078a67786 | ||
|
|
38d1124be9 | ||
|
|
e9d3c218ef | ||
|
|
6d2ca8fe40 | ||
|
|
a06011daf3 | ||
|
|
0846b8b102 | ||
|
|
1dd2b44982 | ||
|
|
d9508e97df | ||
|
|
534ed9c3c2 | ||
|
|
a552df66a9 | ||
|
|
85238d4d98 | ||
|
|
b7e9dd023c | ||
|
|
1ac05f5e4e | ||
|
|
2e4a872272 | ||
|
|
d550364431 | ||
|
|
5b2bf9d74c | ||
|
|
4af1aa3177 | ||
|
|
2fe40679f4 | ||
|
|
7029965d3a | ||
|
|
7e49c70320 | ||
|
|
f7fe5ad1bb | ||
|
|
035c52ce3c | ||
|
|
7e7e38b60e | ||
|
|
36ab133e62 | ||
|
|
e13422ab5e | ||
|
|
f4d5283f70 | ||
|
|
fda79b8e21 | ||
|
|
5a345b01dc | ||
|
|
03f4468be2 | ||
|
|
a3d82f8e2f | ||
|
|
976fe5bc0d | ||
|
|
582b222b00 | ||
|
|
d9e8e839fe | ||
|
|
e8472c8f1a | ||
|
|
deaab5133e | ||
|
|
cffe31fc9d | ||
|
|
0e9c7533fb | ||
|
|
1ffb9152f7 | ||
|
|
51faa6ddb7 | ||
|
|
18d6bc3757 | ||
|
|
7c4ae58517 | ||
|
|
05f8fcf836 | ||
|
|
692c3e1b45 | ||
|
|
acff29fddd | ||
|
|
58659f6c4f | ||
|
|
e410180c6e | ||
|
|
4476b05d59 | ||
|
|
343b0ae576 | ||
|
|
9952350c64 | ||
|
|
3bc78caba9 | ||
|
|
0f1c9ec72a | ||
|
|
80f65d6f77 | ||
|
|
de69f60c6a | ||
|
|
2a653b05a0 | ||
|
|
0f04a82857 | ||
|
|
17903346cf | ||
|
|
98b468da57 | ||
|
|
bccb4c7bd9 | ||
|
|
dc53628faf | ||
|
|
21f339e6eb | ||
|
|
c6831c6b07 | ||
|
|
33da4d84eb | ||
|
|
08de12e962 | ||
|
|
7c83373f1e | ||
|
|
021164fbe5 | ||
|
|
b2d0c21fe0 | ||
|
|
7391e2586a | ||
|
|
3532ce9a25 | ||
|
|
2c769acf8c | ||
|
|
c1b373b931 | ||
|
|
61cb557b18 | ||
|
|
b6cff1aa1c | ||
|
|
4471ad9f6b | ||
|
|
cd57768b08 | ||
|
|
d2206152bb | ||
|
|
a34dc0a0e3 | ||
|
|
881a7b3b69 | ||
|
|
b64824addb | ||
|
|
c7104c9471 | ||
|
|
82bbb1dc4a | ||
|
|
9c351e0444 | ||
|
|
5ed5383338 | ||
|
|
eb1d54871b | ||
|
|
e148c838b0 | ||
|
|
c73df2a7b4 | ||
|
|
bc6c6c9f0c | ||
|
|
89d0a6a67c | ||
|
|
38682e93db | ||
|
|
1febeaca7f | ||
|
|
229dcb082b | ||
|
|
3849aed6fb | ||
|
|
f82db6a894 | ||
|
|
a8a859cf5e | ||
|
|
84df37de97 | ||
|
|
7be96f64ab | ||
|
|
947935e4c9 | ||
|
|
40af1fcfc6 | ||
|
|
021444b322 | ||
|
|
ec7c637cf2 | ||
|
|
0a0779c4a9 | ||
|
|
856c3143f8 | ||
|
|
79f73a23f3 | ||
|
|
a52d9880cc | ||
|
|
4af912f712 | ||
|
|
65f48e0ecd | ||
|
|
08eaba44ca | ||
|
|
05c35c398f | ||
|
|
193c3abf0e | ||
|
|
dac1875a79 | ||
|
|
5b8263e8fb | ||
|
|
26e85b8c88 | ||
|
|
152c04c03d | ||
|
|
12ab6fa43f | ||
|
|
5a55772559 | ||
|
|
e8e61cbbd5 | ||
|
|
d78fa52ad7 | ||
|
|
4ddaa5fc20 | ||
|
|
8f847cb5aa | ||
|
|
d7abcb01bc | ||
|
|
599832cb81 | ||
|
|
8cff7dcdaf | ||
|
|
530f515556 | ||
|
|
601728045c | ||
|
|
b18cd893be | ||
|
|
21390a12b9 | ||
|
|
182bcbae23 | ||
|
|
1c55025b12 | ||
|
|
0900d4bc97 | ||
|
|
be2518d784 | ||
|
|
978f687df9 | ||
|
|
fd1690431f | ||
|
|
3cfcd4ad13 | ||
|
|
69b0b764e3 | ||
|
|
e11cef5fca | ||
|
|
395c02caf4 | ||
|
|
0c4e739e94 | ||
|
|
7a72526e47 | ||
|
|
bdd8883d12 | ||
|
|
5f882b1cdd | ||
|
|
b3d849dd38 | ||
|
|
536b65f02b | ||
|
|
103c42cdb7 | ||
|
|
aa1dd881d8 | ||
|
|
92d27f2fea | ||
|
|
f8de44c35f | ||
|
|
cdaf7b5308 | ||
|
|
f81980e1fa | ||
|
|
e9e54d8f65 | ||
|
|
4b88ce787d | ||
|
|
04bfdf85de | ||
|
|
f9c3470a8d | ||
|
|
c1b131b67e | ||
|
|
16b82ea061 | ||
|
|
f8f370ace6 | ||
|
|
43f67c6164 | ||
|
|
d5c69fb73f | ||
|
|
93f9eb7af2 | ||
|
|
f5be4183ce | ||
|
|
eed031fab0 | ||
|
|
6d5da83c68 | ||
|
|
328f36846e | ||
|
|
5f01dd8d09 | ||
|
|
b596e6a665 | ||
|
|
79d3cf5880 | ||
|
|
f7822c775d | ||
|
|
8c08792f0e | ||
|
|
026bba23f1 | ||
|
|
4305cb9230 | ||
|
|
d7b7c28ae5 | ||
|
|
2886d0dc92 | ||
|
|
d6fd510c49 | ||
|
|
a2a7d5bb01 | ||
|
|
223b2650c4 | ||
|
|
07f1c4e8f8 | ||
|
|
01c1644d9c | ||
|
|
3eff2d4b3f | ||
|
|
9ddf8b96f8 | ||
|
|
3d00fa817a | ||
|
|
0809a2b671 | ||
|
|
c0a1404e4c | ||
|
|
bfed8cb6ed | ||
|
|
09a2648f7e | ||
|
|
ee591195cf | ||
|
|
e974313523 | ||
|
|
1e972b6e0e | ||
|
|
e369cb6e73 | ||
|
|
ec391be4f2 | ||
|
|
697e23422f | ||
|
|
e487b6fe2b | ||
|
|
656f881756 | ||
|
|
cd2aa487a5 | ||
|
|
b7d822972e | ||
|
|
ec63f5d32a | ||
|
|
952ccc5fc8 | ||
|
|
9a2f1f380d | ||
|
|
580b9196e6 | ||
|
|
0d911b9381 | ||
|
|
c6d8aecc0f | ||
|
|
fdd3d112b0 | ||
|
|
2fecb3cb1a | ||
|
|
f3630ea16b | ||
|
|
fd19444761 | ||
|
|
4b1afb41b3 | ||
|
|
f9f453f4d7 | ||
|
|
f508a4bb71 | ||
|
|
5d0fbc47d0 | ||
|
|
1e977426eb | ||
|
|
2640f88f8a | ||
|
|
fa731b10ec | ||
|
|
4117ca349f | ||
|
|
2d475c9bb3 | ||
|
|
6f54011e7b | ||
|
|
760397c429 | ||
|
|
7190ac5127 | ||
|
|
ceaefcb18d | ||
|
|
844ce77cae | ||
|
|
cf3a185b62 | ||
|
|
efc982a48d | ||
|
|
96bc214acd | ||
|
|
15999758a7 | ||
|
|
44aa8c2c5b | ||
|
|
8c6fc5ae52 | ||
|
|
c4561571aa | ||
|
|
40a203843d | ||
|
|
8b5ee54c6a | ||
|
|
03fa495fbc | ||
|
|
5901848944 | ||
|
|
d40f9e57ff | ||
|
|
133cc95f33 | ||
|
|
d30e748e64 | ||
|
|
98d77043d8 | ||
|
|
40d1e7bbfc | ||
|
|
e8275f6e4d | ||
|
|
70dcffa025 | ||
|
|
c94a9b1d8b | ||
|
|
6a9393e8ed | ||
|
|
ab98d0ffc6 | ||
|
|
2ddeb79431 | ||
|
|
92ff9c9108 | ||
|
|
7c58dc89c3 | ||
|
|
b513f7c935 | ||
|
|
f1483f848c | ||
|
|
ea4c9b21b7 | ||
|
|
72edfbc270 | ||
|
|
5ccf2eac40 | ||
|
|
6696b0dfbf | ||
|
|
aead77d597 | ||
|
|
130c27c1da | ||
|
|
f6e1dd44f0 | ||
|
|
1e9973a0c0 | ||
|
|
91761738fd | ||
|
|
cccb2e2fdf | ||
|
|
18138d895e | ||
|
|
95d434d003 | ||
|
|
70c651ebb7 | ||
|
|
8cb62a616a | ||
|
|
fa2b52c974 | ||
|
|
6d306c1946 | ||
|
|
5bf814032f | ||
|
|
bea5e7166c | ||
|
|
003090b70c | ||
|
|
02a4e4099d | ||
|
|
56e0ac02af | ||
|
|
12a70bbefb | ||
|
|
5a4ddb2870 | ||
|
|
42195060e6 | ||
|
|
68fa55f310 | ||
|
|
0b0c3e7e58 | ||
|
|
92434f91c7 | ||
|
|
6414ad4cbb | ||
|
|
ac5aea1c81 | ||
|
|
a75605b8c3 | ||
|
|
7b24275346 | ||
|
|
ed1a576305 | ||
|
|
66c95a65c5 | ||
|
|
62a0d7359b | ||
|
|
2c7d7ebb48 | ||
|
|
8b6fe52f74 | ||
|
|
eabb7f84e9 | ||
|
|
f0a20dbc9c | ||
|
|
15ec77fa79 | ||
|
|
32cd2106d0 | ||
|
|
6857a2e8d4 | ||
|
|
5e8b34ae30 | ||
|
|
a9b682b7c0 | ||
|
|
0aadc456dc | ||
|
|
cac2acae07 | ||
|
|
146b465ec1 | ||
|
|
5aba762a33 | ||
|
|
77b7107d05 | ||
|
|
a663dda869 | ||
|
|
db14f0fa89 | ||
|
|
2488b4c50c | ||
|
|
ed642c72c9 | ||
|
|
9a74ae6280 | ||
|
|
32eb38ebd9 | ||
|
|
2dde65c4ba | ||
|
|
176fbedc69 | ||
|
|
1b15af44b6 | ||
|
|
8336420a26 | ||
|
|
1e971d85c4 | ||
|
|
a6b7569d7a | ||
|
|
9e37c788ef | ||
|
|
ca0a6bbf71 | ||
|
|
a3da3d78d4 | ||
|
|
e1c2d2e65d | ||
|
|
6f194eeabf | ||
|
|
16cbc16998 | ||
|
|
5e6608b48e | ||
|
|
94bc137526 | ||
|
|
276a0f55ee | ||
|
|
dbaf99f3d9 | ||
|
|
97411f5567 | ||
|
|
641330baa6 | ||
|
|
2074fc3ff9 | ||
|
|
35e680cd3f | ||
|
|
705d88eaba | ||
|
|
8fef44333b | ||
|
|
3271d8f6e2 | ||
|
|
3622381f8c | ||
|
|
f2729b0610 | ||
|
|
cd44547573 | ||
|
|
3361691d0a | ||
|
|
81d472f6f9 | ||
|
|
d458968cee | ||
|
|
b6a2257758 | ||
|
|
5eb01da0a0 | ||
|
|
5aaf361139 | ||
|
|
6a8dcbc392 | ||
|
|
12babcc1c2 | ||
|
|
416aa1d2d7 | ||
|
|
06d9c584a3 | ||
|
|
8e16bb4ddc | ||
|
|
e1dee439bb | ||
|
|
e313d012ae | ||
|
|
dede619b9e | ||
|
|
142cfb39fc | ||
|
|
53d41a456a | ||
|
|
95b34ca940 | ||
|
|
3eaf76eebd | ||
|
|
5c12d36be3 | ||
|
|
1ee68eb318 | ||
|
|
705c7f0a4b | ||
|
|
8c5e49efc0 | ||
|
|
483e09cf1c | ||
|
|
bbb68d0072 | ||
|
|
b0381b3705 | ||
|
|
f346379c7b | ||
|
|
b1c31e1aac | ||
|
|
02b6f9c335 | ||
|
|
d14d9919c7 | ||
|
|
3984f74eb4 | ||
|
|
ebdced6175 | ||
|
|
1a702075ba | ||
|
|
bd79e3d383 | ||
|
|
10f72417c9 | ||
|
|
87ad869a8a | ||
|
|
bc4659b73c | ||
|
|
4eab6536c3 | ||
|
|
1571c8a781 | ||
|
|
20a65cbe32 | ||
|
|
07e15a0038 | ||
|
|
5918cfaa20 | ||
|
|
73fa465c26 | ||
|
|
e8a221d227 | ||
|
|
b734a7d155 | ||
|
|
bbe4022566 | ||
|
|
63f3abfbe8 | ||
|
|
22added5fa | ||
|
|
3a3b53e11d | ||
|
|
ddcea63d0f | ||
|
|
e800f90d7c | ||
|
|
6d16147d60 | ||
|
|
9ed1fe59f2 | ||
|
|
f805526336 | ||
|
|
2e86134c0b | ||
|
|
5f768742a0 | ||
|
|
7a8c086d44 | ||
|
|
1d4e12bc6b | ||
|
|
70b0f50d13 | ||
|
|
149c4308bb | ||
|
|
9d4fac088c | ||
|
|
eb27acaa65 | ||
|
|
2362aa1a7a | ||
|
|
f414e57d82 | ||
|
|
13543df649 | ||
|
|
1d7fdde81d | ||
|
|
5326736571 | ||
|
|
78d07b0bd2 | ||
|
|
51ff4713b3 | ||
|
|
c0f70204d1 | ||
|
|
2575aa5120 | ||
|
|
1f6401ee0a | ||
|
|
248ff82f83 | ||
|
|
f1db7d7fa2 | ||
|
|
0bcc3ee4e9 | ||
|
|
0bd651abda | ||
|
|
334ca18171 | ||
|
|
ff978ce4d8 | ||
|
|
128ebe630b | ||
|
|
6371081593 | ||
|
|
31d8bd7a5e | ||
|
|
dee58cfefd | ||
|
|
71f1fdb668 | ||
|
|
85488d69e2 | ||
|
|
5c7e6689fc | ||
|
|
5b3fb6ac56 | ||
|
|
65839235ce | ||
|
|
d1cd8047fa | ||
|
|
90ed9f5387 | ||
|
|
04d28a9362 | ||
|
|
fb89129fb2 | ||
|
|
399b69a309 | ||
|
|
01ab70d204 | ||
|
|
45553556d5 | ||
|
|
996fa777bd | ||
|
|
dc1336dbc2 | ||
|
|
b1f89a5cb8 | ||
|
|
48f7abf697 | ||
|
|
2159fbee56 | ||
|
|
7fcab3d52e | ||
|
|
2d42d7835d | ||
|
|
ed83825223 | ||
|
|
beee34055a | ||
|
|
7abd106c8a | ||
|
|
be2208f208 | ||
|
|
316ba5f75e | ||
|
|
a08b6306d3 | ||
|
|
21e71af13f | ||
|
|
f352b2a7ed | ||
|
|
7bf1ad1a5a | ||
|
|
9de601f377 | ||
|
|
df5086196f | ||
|
|
a427d7d852 | ||
|
|
efbcca3cb6 | ||
|
|
c65cc91f5b | ||
|
|
d5f65ba62e | ||
|
|
ef9c984bcd | ||
|
|
3074a4b02d | ||
|
|
fdbc6b6c13 | ||
|
|
ea584992d5 | ||
|
|
96b4c763e4 | ||
|
|
0b55275418 | ||
|
|
1963733311 | ||
|
|
a06bbafd6a | ||
|
|
250f7acc98 | ||
|
|
82f8a7c56a | ||
|
|
b345488272 | ||
|
|
1de4020dc9 | ||
|
|
dc6ed8716d | ||
|
|
a8a9b2ae75 | ||
|
|
e03a30bd85 | ||
|
|
16357c5666 | ||
|
|
131cc17384 | ||
|
|
c18b474bbf | ||
|
|
e3b1ad5591 | ||
|
|
e6f1bb7dad | ||
|
|
730143e39b | ||
|
|
5cd00a50b2 | ||
|
|
3b8b3f9034 | ||
|
|
bbe0b17b93 | ||
|
|
7446569cf4 | ||
|
|
930c2e093c | ||
|
|
2154b513af | ||
|
|
93508438fa | ||
|
|
1490b2c3bb | ||
|
|
760abfc316 | ||
|
|
a1c15778ae | ||
|
|
4f9c104ec9 | ||
|
|
627113dc60 | ||
|
|
234829644c | ||
|
|
af4ecbadab | ||
|
|
b20743b352 | ||
|
|
e546cdef51 | ||
|
|
5f3e17152b | ||
|
|
0d6ff230da | ||
|
|
14da92cf6b | ||
|
|
563f3bdd85 | ||
|
|
8bed63090b | ||
|
|
4f28ad6ccc | ||
|
|
3f98633704 | ||
|
|
e7758866c9 | ||
|
|
1b1d1a246f | ||
|
|
db175020e0 | ||
|
|
44bea09b10 | ||
|
|
aee197f027 | ||
|
|
38c0f2b205 | ||
|
|
3dfbce1f40 | ||
|
|
ad2cbd6afe | ||
|
|
f34215d56a | ||
|
|
163aef158b | ||
|
|
40f613199a | ||
|
|
ed230264fb | ||
|
|
03948f891e | ||
|
|
7dfa140542 | ||
|
|
01e7e45744 | ||
|
|
25135d429f | ||
|
|
7c1593742c | ||
|
|
5685dc05f6 | ||
|
|
f980682829 | ||
|
|
b600c01bca | ||
|
|
ad43cc04ff | ||
|
|
c45402c1eb | ||
|
|
a35ce43a61 | ||
|
|
ed32b4c812 | ||
|
|
4ad5d3edbd | ||
|
|
355a4a126b | ||
|
|
edaa05a217 | ||
|
|
c4456a2863 | ||
|
|
2bf0f64295 | ||
|
|
12705b5c3e | ||
|
|
913700b116 | ||
|
|
0540485b14 | ||
|
|
e5228ba66f | ||
|
|
e09f126abf | ||
|
|
acdbbdacab | ||
|
|
6a267f588c | ||
|
|
692277e72c | ||
|
|
47267b0da5 | ||
|
|
8bb1454d5d | ||
|
|
5861b0575d | ||
|
|
afe0d1c810 | ||
|
|
0b6ab2d1a7 | ||
|
|
183f4a5211 | ||
|
|
84afd6c937 | ||
|
|
7065070838 | ||
|
|
3e18990e90 | ||
|
|
6b481be074 | ||
|
|
52f5528d3a | ||
|
|
0db4a3936f | ||
|
|
ccc2993610 | ||
|
|
b7c0e97e71 | ||
|
|
6c7e854797 | ||
|
|
efb74f3ba3 | ||
|
|
270e7a4234 | ||
|
|
decbd93af4 | ||
|
|
4770008cb7 | ||
|
|
1413111099 | ||
|
|
60cf2c785f | ||
|
|
ee7ddac7a2 | ||
|
|
e7de028d2d | ||
|
|
e39a9ba199 | ||
|
|
65a55cea7e | ||
|
|
9e6bc35944 | ||
|
|
c289b79fb2 | ||
|
|
03a728dfc8 | ||
|
|
558ebcdc83 | ||
|
|
4b06fb2424 | ||
|
|
474218395a | ||
|
|
70092b9800 | ||
|
|
cd13addcfc | ||
|
|
5b6a1d7a40 | ||
|
|
74ffc25b50 | ||
|
|
91de49e6a6 | ||
|
|
102484dea8 | ||
|
|
f9b9a14275 | ||
|
|
8b3d5848a2 | ||
|
|
9c5d676111 | ||
|
|
84ad007de3 | ||
|
|
e88d261dca | ||
|
|
7a56ca13f8 | ||
|
|
be2d99e5f6 | ||
|
|
0a663da5b6 | ||
|
|
0b3fc57458 | ||
|
|
37f60be836 | ||
|
|
9f5b38f539 | ||
|
|
665e5c49ea | ||
|
|
3a10e07dfc | ||
|
|
909de45c5c | ||
|
|
5aa7f75f77 | ||
|
|
71af666c38 | ||
|
|
55971d2f05 | ||
|
|
0723e664e1 | ||
|
|
02174fb68f | ||
|
|
92c51de734 | ||
|
|
ce8de6df7f | ||
|
|
d1e5c59af9 | ||
|
|
e792777187 | ||
|
|
afa837a361 | ||
|
|
5a9bd0904b | ||
|
|
b50d06ae58 | ||
|
|
220201cf14 | ||
|
|
5fa3a92ecb | ||
|
|
fef46263b5 | ||
|
|
e6d9f99ac0 | ||
|
|
244e7c7c29 | ||
|
|
fa583f6533 | ||
|
|
67fc57b5e1 | ||
|
|
b4547888d9 | ||
|
|
7277afefb9 | ||
|
|
08149ea0b9 | ||
|
|
06844484dd | ||
|
|
23602784f8 | ||
|
|
f8bcd2d200 |
@@ -12,21 +12,33 @@
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.10",
|
||||
"branchName": "2.10.x",
|
||||
"slug": "2.10",
|
||||
"name": "2.12",
|
||||
"branchName": "2.12.x",
|
||||
"slug": "2.12",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.9",
|
||||
"branchName": "2.9.x",
|
||||
"slug": "2.9",
|
||||
"name": "2.11",
|
||||
"branchName": "2.11.x",
|
||||
"slug": "2.11",
|
||||
"current": true,
|
||||
"aliases": [
|
||||
"current",
|
||||
"stable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "2.10",
|
||||
"branchName": "2.10.x",
|
||||
"slug": "2.10",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.9",
|
||||
"branchName": "2.9.x",
|
||||
"slug": "2.9",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.8",
|
||||
"branchName": "2.8.x",
|
||||
|
||||
30
.github/workflows/coding-standard.yml
vendored
30
.github/workflows/coding-standard.yml
vendored
@@ -10,30 +10,6 @@ on:
|
||||
|
||||
jobs:
|
||||
coding-standards:
|
||||
name: "Coding Standards"
|
||||
runs-on: "ubuntu-20.04"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "7.4"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v2"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
tools: "cs2pr"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
# https://github.com/doctrine/.github/issues/3
|
||||
- name: "Run PHP_CodeSniffer"
|
||||
run: "vendor/bin/phpcs -q --no-colors --report=checkstyle | cs2pr"
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@1.4.1"
|
||||
with:
|
||||
php-version: "8.1"
|
||||
|
||||
70
.github/workflows/continuous-integration.yml
vendored
70
.github/workflows/continuous-integration.yml
vendored
@@ -2,7 +2,11 @@ name: "Continuous Integration"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*.x"
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
|
||||
env:
|
||||
fail-fast: true
|
||||
@@ -19,6 +23,14 @@ jobs:
|
||||
- "7.3"
|
||||
- "7.4"
|
||||
- "8.0"
|
||||
- "8.1"
|
||||
dbal-version:
|
||||
- "default"
|
||||
include:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
- php-version: "8.1"
|
||||
dbal-version: "3@dev"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
@@ -30,10 +42,14 @@ jobs:
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
extensions: "pdo, pdo_sqlite"
|
||||
extensions: "apcu, pdo, pdo_sqlite"
|
||||
coverage: "pcov"
|
||||
ini-values: "zend.assertions=1"
|
||||
|
||||
- name: "Require specific DBAL version"
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
|
||||
@@ -50,7 +66,7 @@ jobs:
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v2"
|
||||
with:
|
||||
name: "phpunit-sqlite-${{ matrix.php-version }}-coverage"
|
||||
name: "phpunit-sqlite-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
|
||||
|
||||
@@ -62,10 +78,16 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "7.4"
|
||||
- "8.1"
|
||||
dbal-version:
|
||||
- "default"
|
||||
postgres-version:
|
||||
- "9.6"
|
||||
- "13"
|
||||
- "14"
|
||||
include:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
postgres-version: "14"
|
||||
|
||||
services:
|
||||
postgres:
|
||||
@@ -92,6 +114,10 @@ jobs:
|
||||
coverage: "pcov"
|
||||
ini-values: "zend.assertions=1"
|
||||
|
||||
- name: "Require specific DBAL version"
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
|
||||
@@ -101,7 +127,7 @@ jobs:
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v2"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-coverage"
|
||||
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage.xml"
|
||||
|
||||
|
||||
@@ -113,12 +139,19 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "7.4"
|
||||
- "8.1"
|
||||
dbal-version:
|
||||
- "default"
|
||||
mariadb-version:
|
||||
- "10.5"
|
||||
- "10.6"
|
||||
extension:
|
||||
- "mysqli"
|
||||
- "pdo_mysql"
|
||||
include:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
mariadb-version: "10.6"
|
||||
extension: "pdo_mysql"
|
||||
|
||||
services:
|
||||
mariadb:
|
||||
@@ -139,6 +172,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: "Require specific DBAL version"
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
@@ -156,7 +193,7 @@ jobs:
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v2"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-coverage"
|
||||
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage.xml"
|
||||
|
||||
|
||||
@@ -168,13 +205,20 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- "7.4"
|
||||
- "8.1"
|
||||
dbal-version:
|
||||
- "default"
|
||||
mysql-version:
|
||||
- "5.7"
|
||||
- "8.0"
|
||||
extension:
|
||||
- "mysqli"
|
||||
- "pdo_mysql"
|
||||
include:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
mysql-version: "8.0"
|
||||
extension: "pdo_mysql"
|
||||
|
||||
services:
|
||||
mysql:
|
||||
@@ -202,6 +246,10 @@ jobs:
|
||||
ini-values: "zend.assertions=1"
|
||||
extensions: "${{ matrix.extension }}"
|
||||
|
||||
- name: "Require specific DBAL version"
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
|
||||
@@ -218,9 +266,10 @@ jobs:
|
||||
- name: "Upload coverage files"
|
||||
uses: "actions/upload-artifact@v2"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-coverage"
|
||||
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
|
||||
|
||||
phpunit-lower-php-versions:
|
||||
name: "PHPUnit with SQLite"
|
||||
runs-on: "ubuntu-20.04"
|
||||
@@ -253,6 +302,7 @@ jobs:
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite.xml"
|
||||
|
||||
|
||||
upload_coverage:
|
||||
name: "Upload coverage to Codecov"
|
||||
runs-on: "ubuntu-20.04"
|
||||
|
||||
@@ -7,40 +7,9 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: "Git tag, release & create merge-up PR"
|
||||
runs-on: "ubuntu-20.04"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v2"
|
||||
|
||||
- name: "Release"
|
||||
uses: "laminas/automatic-releases@v1"
|
||||
with:
|
||||
command-name: "laminas:automatic-releases:release"
|
||||
env:
|
||||
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
|
||||
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
|
||||
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
"SHELL_VERBOSITY": "3"
|
||||
|
||||
- name: "Create Merge-Up Pull Request"
|
||||
uses: "laminas/automatic-releases@v1"
|
||||
with:
|
||||
command-name: "laminas:automatic-releases:create-merge-up-pull-request"
|
||||
env:
|
||||
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
|
||||
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
|
||||
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
|
||||
- name: "Create new milestones"
|
||||
uses: "laminas/automatic-releases@v1"
|
||||
with:
|
||||
command-name: "laminas:automatic-releases:create-milestones"
|
||||
env:
|
||||
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
|
||||
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
|
||||
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@1.4.1"
|
||||
secrets:
|
||||
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
ORGANIZATION_ADMIN_TOKEN: ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
|
||||
SIGNING_SECRET_KEY: ${{ secrets.SIGNING_SECRET_KEY }}
|
||||
|
||||
34
.github/workflows/static-analysis.yml
vendored
34
.github/workflows/static-analysis.yml
vendored
@@ -15,9 +15,21 @@ jobs:
|
||||
runs-on: "ubuntu-20.04"
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.0"
|
||||
- "8.1"
|
||||
dbal-version:
|
||||
- "default"
|
||||
persistence-version:
|
||||
- "default"
|
||||
include:
|
||||
- php-version: "8.1"
|
||||
dbal-version: "2.13"
|
||||
persistence-version: "default"
|
||||
- php-version: "8.1"
|
||||
dbal-version: "default"
|
||||
persistence-version: "2.5"
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
@@ -29,6 +41,14 @@ jobs:
|
||||
coverage: "none"
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
|
||||
- name: "Require specific DBAL version"
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Require specific persistence version"
|
||||
run: "composer require doctrine/persistence ^${{ matrix.persistence-version }} --no-update"
|
||||
if: "${{ matrix.persistence-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
with:
|
||||
@@ -36,15 +56,25 @@ jobs:
|
||||
|
||||
- name: "Run a static analysis with phpstan/phpstan"
|
||||
run: "vendor/bin/phpstan analyse"
|
||||
if: "${{ matrix.dbal-version == 'default' && matrix.persistence-version == 'default'}}"
|
||||
|
||||
- name: "Run a static analysis with phpstan/phpstan"
|
||||
run: "vendor/bin/phpstan analyse -c phpstan-dbal2.neon"
|
||||
if: "${{ matrix.dbal-version == '2.13' }}"
|
||||
|
||||
- name: "Run a static analysis with phpstan/phpstan"
|
||||
run: "vendor/bin/phpstan analyse -c phpstan-persistence2.neon"
|
||||
if: "${{ matrix.dbal-version == 'default' && matrix.persistence-version != 'default'}}"
|
||||
|
||||
static-analysis-psalm:
|
||||
name: "Static Analysis with Psalm"
|
||||
runs-on: "ubuntu-20.04"
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-version:
|
||||
- "8.0"
|
||||
- "8.1"
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -15,5 +15,5 @@ vendor/
|
||||
/tests/Doctrine/Performance/history.db
|
||||
/.phpcs-cache
|
||||
composer.lock
|
||||
/.phpunit.result.cache
|
||||
.phpunit.result.cache
|
||||
/*.phpunit.xml
|
||||
|
||||
@@ -37,8 +37,7 @@ will have to run a composer installation in the project:
|
||||
```sh
|
||||
git clone git@github.com:doctrine/orm.git
|
||||
cd orm
|
||||
curl -sS https://getcomposer.org/installer | php --
|
||||
./composer.phar install
|
||||
composer install
|
||||
```
|
||||
|
||||
To run the testsuite against another database, copy the ``phpunit.xml.dist``
|
||||
|
||||
26
README.md
26
README.md
@@ -1,7 +1,9 @@
|
||||
| [3.0.x][3.0] | [2.10.x][2.10] | [2.9.x][2.9] |
|
||||
| [3.0.x][3.0] | [2.12.x][2.12] | [2.11.x][2.11] |
|
||||
|:----------------:|:----------------:|:----------:|
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.10 image]][2.10] | [![Build status][2.9 image]][2.9] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.10 coverage image]][2.10 coverage] | [![Coverage Status][2.9 coverage image]][2.9 coverage] |
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.12 image]][2.12] | [![Build status][2.11 image]][2.11] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.12 coverage image]][2.12 coverage] | [![Coverage Status][2.11 coverage image]][2.11 coverage] |
|
||||
|
||||
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
|
||||
|
||||
Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence
|
||||
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
|
||||
@@ -13,18 +15,18 @@ without requiring unnecessary code duplication.
|
||||
## More resources:
|
||||
|
||||
* [Website](http://www.doctrine-project.org)
|
||||
* [Documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/index.html)
|
||||
* [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.9 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.9.x
|
||||
[2.9]: https://github.com/doctrine/orm/tree/2.9.x
|
||||
[2.9 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.9.x/graph/badge.svg
|
||||
[2.9 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.9.x
|
||||
[2.10 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.10.x
|
||||
[2.10]: https://github.com/doctrine/orm/tree/2.10.x
|
||||
[2.10 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.10.x/graph/badge.svg
|
||||
[2.10 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.10.x
|
||||
[2.12 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.12.x
|
||||
[2.12]: https://github.com/doctrine/orm/tree/2.12.x
|
||||
[2.12 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.12.x/graph/badge.svg
|
||||
[2.12 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.12.x
|
||||
[2.11 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.11.x
|
||||
[2.11]: https://github.com/doctrine/orm/tree/2.11.x
|
||||
[2.11 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.11.x/graph/badge.svg
|
||||
[2.11 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.11.x
|
||||
|
||||
@@ -10,8 +10,8 @@ we cannot protect you from SQL injection.
|
||||
Please read the documentation chapter on Security in Doctrine DBAL and ORM to
|
||||
understand the assumptions we make.
|
||||
|
||||
- [DBAL Security Page](https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/security.html)
|
||||
- [ORM Security Page](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/security.html)
|
||||
- [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
|
||||
|
||||
259
UPGRADE.md
259
UPGRADE.md
@@ -1,3 +1,235 @@
|
||||
# Upgrade to 2.12
|
||||
|
||||
## Deprecated the `doctrine` binary.
|
||||
|
||||
The documentation explains how the console tools can be bootstrapped for
|
||||
standalone usage.
|
||||
|
||||
The method `ConsoleRunner::printCliConfigTemplate()` is deprecated because it
|
||||
was only useful in the context of the `doctrine` binary.
|
||||
|
||||
## Deprecate omitting `$class` argument to `ORMInvalidArgumentException::invalidIdentifierBindingEntity()`
|
||||
|
||||
To make it easier to identify understand the cause for that exception, it is
|
||||
deprecated to omit the class name when calling
|
||||
`ORMInvalidArgumentException::invalidIdentifierBindingEntity()`.
|
||||
|
||||
## Deprecate `Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper`
|
||||
|
||||
Using a console helper to provide the ORM's console commands with one or
|
||||
multiple entity managers had been deprecated with 2.9 already. This leaves
|
||||
The `EntityManagerHelper` class with no purpose which is why it is now
|
||||
deprecated too. Applications that still rely on the `em` console helper, can
|
||||
easily recreate that class in their own codebase.
|
||||
|
||||
## Deprecate custom repository classes that don't extend `EntityRepository`
|
||||
|
||||
Although undocumented, it is currently possible to configure a custom repository
|
||||
class that implements `ObjectRepository` but does not extend the
|
||||
`EntityRepository` base class.
|
||||
|
||||
This is now deprecated. Please extend `EntityRepository` instead.
|
||||
|
||||
## Deprecated more APIs related to entity namespace aliases
|
||||
|
||||
```diff
|
||||
-$config = $entityManager->getConfiguration();
|
||||
-$config->addEntityNamespace('CMS', 'My\App\Cms');
|
||||
+use My\App\Cms\CmsUser;
|
||||
|
||||
-$entityManager->getRepository('CMS:CmsUser');
|
||||
+$entityManager->getRepository(CmsUser::class);
|
||||
```
|
||||
|
||||
## Deprecate `AttributeDriver::getReader()` and `AnnotationDriver::getReader()`
|
||||
|
||||
That method was inherited from the abstract `AnnotationDriver` class of
|
||||
`doctrine/persistence`, and does not seem to serve any purpose.
|
||||
|
||||
## Un-deprecate `Doctrine\ORM\Proxy\Proxy`
|
||||
|
||||
Because no forward-compatible new proxy solution had been implemented yet, the
|
||||
current proxy mechanism is not considered deprecated anymore for the time
|
||||
being. This applies to the following interfaces/classes:
|
||||
|
||||
* `Doctrine\ORM\Proxy\Proxy`
|
||||
* `Doctrine\ORM\Proxy\ProxyFactory`
|
||||
|
||||
These methods have been un-deprecated:
|
||||
|
||||
* `Doctrine\ORM\Configuration::getAutoGenerateProxyClasses()`
|
||||
* `Doctrine\ORM\Configuration::getProxyDir()`
|
||||
* `Doctrine\ORM\Configuration::getProxyNamespace()`
|
||||
|
||||
Note that the `Doctrine\ORM\Proxy\Autoloader` remains deprecated and will be removed in 3.0.
|
||||
|
||||
## Deprecate helper methods from `AbstractCollectionPersister`
|
||||
|
||||
The following protected methods of
|
||||
`Doctrine\ORM\Cache\Persister\Collection\AbstractCollectionPersister`
|
||||
are not in use anymore and will be removed.
|
||||
|
||||
* `evictCollectionCache()`
|
||||
* `evictElementCache()`
|
||||
|
||||
## Deprecate `Doctrine\ORM\Query\TreeWalkerChainIterator`
|
||||
|
||||
This class won't have a replacement.
|
||||
|
||||
## Deprecate `OnClearEventArgs::getEntityClass()` and `OnClearEventArgs::clearsAllEntities()`
|
||||
|
||||
These methods will be removed in 3.0 along with the ability to partially clear
|
||||
the entity manager.
|
||||
|
||||
## Deprecate `Doctrine\ORM\Configuration::newDefaultAnnotationDriver`
|
||||
|
||||
This functionality has been moved to the new `ORMSetup` class. Call
|
||||
`Doctrine\ORM\ORMSetup::createDefaultAnnotationDriver()` to create
|
||||
a new annotation driver.
|
||||
|
||||
## Deprecate `Doctrine\ORM\Tools\Setup`
|
||||
|
||||
In our effort to migrate from Doctrine Cache to PSR-6, the `Setup` class which
|
||||
accepted a Doctrine Cache instance in each method has been deprecated.
|
||||
|
||||
The replacement is `Doctrine\ORM\ORMSetup` which accepts a PSR-6
|
||||
cache instead.
|
||||
|
||||
## Deprecate `Doctrine\ORM\Cache\MultiGetRegion`
|
||||
|
||||
The interface will be merged with `Doctrine\ORM\Cache\Region` in 3.0.
|
||||
|
||||
# Upgrade to 2.11
|
||||
|
||||
## Rename `AbstractIdGenerator::generate()` to `generateId()`
|
||||
|
||||
Implementations of `AbstractIdGenerator` have to override the method
|
||||
`generateId()` without calling the parent implementation. Not doing so is
|
||||
deprecated. Calling `generate()` on any `AbstractIdGenerator` implementation
|
||||
is deprecated.
|
||||
|
||||
## PSR-6-based second level cache
|
||||
|
||||
The second level cache has been reworked to consume a PSR-6 cache. Using a
|
||||
Doctrine Cache instance is deprecated.
|
||||
|
||||
* `DefaultCacheFactory`: The constructor expects a PSR-6 cache item pool as
|
||||
second argument now.
|
||||
* `DefaultMultiGetRegion`: This class is deprecated in favor of `DefaultRegion`.
|
||||
* `DefaultRegion`:
|
||||
* The constructor expects a PSR-6 cache item pool as second argument now.
|
||||
* The protected `$cache` property is deprecated.
|
||||
* The properties `$name` and `$lifetime` as well as the constant
|
||||
`REGION_KEY_SEPARATOR` and the method `getCacheEntryKey()` are flagged as
|
||||
`@internal` now. They all will become `private` in 3.0.
|
||||
* The method `getCache()` is deprecated without replacement.
|
||||
|
||||
## Deprecated: `Doctrine\ORM\Mapping\Driver\PHPDriver`
|
||||
|
||||
Use `StaticPHPDriver` instead when you want to programmatically configure
|
||||
entity metadata.
|
||||
|
||||
You can convert mappings with the `orm:convert-mapping` command or more simply
|
||||
in this case, `include` the metadata file from the `loadMetadata` static method
|
||||
used by the `StaticPHPDriver`.
|
||||
|
||||
## Deprecated: `Setup::registerAutoloadDirectory()`
|
||||
|
||||
Use Composer's autoloader instead.
|
||||
|
||||
## Deprecated: `AbstractHydrator::hydrateRow()`
|
||||
|
||||
Following the deprecation of the method `AbstractHydrator::iterate()`, the
|
||||
method `hydrateRow()` has been deprecated as well.
|
||||
|
||||
## Deprecate cache settings inspection
|
||||
|
||||
Doctrine does not provide its own cache implementation anymore and relies on
|
||||
the PSR-6 standard instead. As a consequence, we cannot determine anymore
|
||||
whether a given cache adapter is suitable for a production environment.
|
||||
Because of that, functionality that aims to do so has been deprecated:
|
||||
|
||||
* `Configuration::ensureProductionSettings()`
|
||||
* the `orm:ensure-production-settings` console command
|
||||
|
||||
# Upgrade to 2.10
|
||||
|
||||
## BC Break: `UnitOfWork` now relies on SPL object IDs, not hashes
|
||||
|
||||
When calling the following methods, you are now supposed to use the result of
|
||||
`spl_object_id()`, and not `spl_object_hash()`:
|
||||
- `UnitOfWork::clearEntityChangeSet()`
|
||||
- `UnitOfWork::setOriginalEntityProperty()`
|
||||
|
||||
## BC Break: Removed `TABLE` id generator strategy
|
||||
|
||||
The implementation was unfinished for 14 years.
|
||||
It is now deprecated to rely on:
|
||||
- `Doctrine\ORM\Id\TableGenerator`;
|
||||
- `Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_TABLE`;
|
||||
- `Doctrine\ORM\Mapping\ClassMetadata::$tableGeneratorDefinition`;
|
||||
- or `Doctrine\ORM\Mapping\ClassMetadata::isIdGeneratorTable()`.
|
||||
|
||||
## New method `Doctrine\ORM\EntityManagerInterface#wrapInTransaction($func)`
|
||||
|
||||
Works the same as `Doctrine\ORM\EntityManagerInterface#transactional()` but returns any value returned from `$func` closure rather than just _non-empty value returned from the closure or true_.
|
||||
|
||||
Because of BC policy, the method does not exist on the interface yet. This is the example of safe usage:
|
||||
|
||||
```php
|
||||
function foo(EntityManagerInterface $entityManager, callable $func) {
|
||||
if (method_exists($entityManager, 'wrapInTransaction')) {
|
||||
return $entityManager->wrapInTransaction($func);
|
||||
}
|
||||
|
||||
return $entityManager->transactional($func);
|
||||
}
|
||||
```
|
||||
|
||||
`Doctrine\ORM\EntityManagerInterface#transactional()` has been deprecated.
|
||||
|
||||
## Minor BC BREAK: some exception methods have been removed
|
||||
|
||||
The following methods were not in use and are very unlikely to be used by
|
||||
downstream packages or applications, and were consequently removed:
|
||||
|
||||
- `ORMException::entityMissingForeignAssignedId`
|
||||
- `ORMException::entityMissingAssignedIdForField`
|
||||
- `ORMException::invalidFlushMode`
|
||||
|
||||
## Deprecated: database-side UUID generation
|
||||
|
||||
[DB-generated UUIDs are deprecated as of `doctrine/dbal` 2.8][DBAL deprecation].
|
||||
As a consequence, using the `UUID` strategy for generating identifiers is deprecated as well.
|
||||
Furthermore, relying on the following classes and methods is deprecated:
|
||||
|
||||
- `Doctrine\ORM\Id\UuidGenerator`
|
||||
- `Doctrine\ORM\Mapping\ClassMetadataInfo::isIdentifierUuid()`
|
||||
|
||||
[DBAL deprecation]: https://github.com/doctrine/dbal/pull/3212
|
||||
|
||||
## Minor BC BREAK: Custom hydrators and `toIterable()`
|
||||
|
||||
The type declaration of the `$stmt` parameter of `AbstractHydrator::toIterable()` has been removed. This change might
|
||||
break custom hydrator implementations that override this very method.
|
||||
|
||||
Overriding this method is not recommended, which is why the method is documented as `@final` now.
|
||||
|
||||
```diff
|
||||
- public function toIterable(ResultStatement $stmt, ResultSetMapping $resultSetMapping, array $hints = []): iterable
|
||||
+ public function toIterable($stmt, ResultSetMapping $resultSetMapping, array $hints = []): iterable
|
||||
```
|
||||
|
||||
## Deprecated: Entity Namespace Aliases
|
||||
|
||||
Entity namespace aliases are deprecated, use the magic ::class constant to abbreviate full class names
|
||||
in EntityManager, EntityRepository and DQL.
|
||||
|
||||
```diff
|
||||
- $entityManager->find('MyBundle:User', $id);
|
||||
+ $entityManager->find(User::class, $id);
|
||||
```
|
||||
|
||||
# Upgrade to 2.9
|
||||
|
||||
## Minor BC BREAK: Setup tool needs cache implementation
|
||||
@@ -33,10 +265,10 @@ now always cleared regardless of the cache adapter being used.
|
||||
Method `Doctrine\ORM\UnitOfWork#commit()` can throw an OptimisticLockException when a commit silently fails and returns false
|
||||
since `Doctrine\DBAL\Connection#commit()` signature changed from returning void to boolean
|
||||
|
||||
## Deprecated: `Doctrine\ORM\AbstractQuery#iterator()`
|
||||
## Deprecated: `Doctrine\ORM\AbstractQuery#iterate()`
|
||||
|
||||
The method `Doctrine\ORM\AbstractQuery#iterator()` is deprecated in favor of `Doctrine\ORM\AbstractQuery#toIterable()`.
|
||||
Note that `toIterable()` yields results of the query, unlike `iterator()` which yielded each result wrapped into an array.
|
||||
The method `Doctrine\ORM\AbstractQuery#iterate()` is deprecated in favor of `Doctrine\ORM\AbstractQuery#toIterable()`.
|
||||
Note that `toIterable()` yields results of the query, unlike `iterate()` which yielded each result wrapped into an array.
|
||||
|
||||
# Upgrade to 2.7
|
||||
|
||||
@@ -104,27 +336,18 @@ These methods have been deprecated:
|
||||
## Deprecated `Doctrine\ORM\Version`
|
||||
|
||||
The `Doctrine\ORM\Version` class is now deprecated and will be removed in Doctrine ORM 3.0:
|
||||
please refrain from checking the ORM version at runtime or use
|
||||
[ocramius/package-versions](https://github.com/Ocramius/PackageVersions/).
|
||||
please refrain from checking the ORM version at runtime or use Composer's [runtime API](https://getcomposer.org/doc/07-runtime.md#knowing-whether-package-x-is-installed-in-version-y).
|
||||
|
||||
## Deprecated `EntityManager#merge()` and `EntityManager#detach()` methods
|
||||
## Deprecated `EntityManager#merge()` method
|
||||
|
||||
Merge and detach semantics were a poor fit for the PHP "share-nothing" architecture.
|
||||
In addition to that, merging/detaching caused multiple issues with data integrity
|
||||
Merge semantics was a poor fit for the PHP "share-nothing" architecture.
|
||||
In addition to that, merging caused multiple issues with data integrity
|
||||
in the managed entity graph, which was constantly spawning more edge-case bugs/scenarios.
|
||||
|
||||
The following API methods were therefore deprecated:
|
||||
|
||||
* `EntityManager#merge()`
|
||||
* `EntityManager#detach()`
|
||||
* `UnitOfWork#merge()`
|
||||
* `UnitOfWork#detach()`
|
||||
|
||||
Users are encouraged to migrate `EntityManager#detach()` calls to `EntityManager#clear()`.
|
||||
|
||||
In order to maintain performance on batch processing jobs, it is endorsed to enable
|
||||
the second level cache (http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second-level-cache.html)
|
||||
on entities that are frequently reused across multiple `EntityManager#clear()` calls.
|
||||
|
||||
An alternative to `EntityManager#merge()` will not be provided by ORM 3.0, since the merging
|
||||
semantics should be part of the business domain rather than the persistence domain of an
|
||||
@@ -167,8 +390,8 @@ If you would still like to perform batching operations over small `UnitOfWork`
|
||||
instances, it is suggested to follow these paths instead:
|
||||
|
||||
* eagerly use `EntityManager#clear()` in conjunction with a specific second level
|
||||
cache configuration (see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second-level-cache.html)
|
||||
* use an explicit change tracking policy (see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/change-tracking-policies.html)
|
||||
cache configuration (see http://docs.doctrine-project.org/projects/doctrine-orm/en/stable/reference/second-level-cache.html)
|
||||
* use an explicit change tracking policy (see http://docs.doctrine-project.org/projects/doctrine-orm/en/stable/reference/change-tracking-policies.html)
|
||||
|
||||
## Deprecated `YAML` mapping drivers.
|
||||
|
||||
|
||||
@@ -1,21 +1,14 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
fwrite(
|
||||
STDERR,
|
||||
'[Warning] The use of this script is discouraged. See'
|
||||
. ' https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/tools.html#doctrine-console'
|
||||
. ' for instructions on bootstrapping the console runner.'
|
||||
. PHP_EOL
|
||||
);
|
||||
|
||||
echo PHP_EOL . PHP_EOL;
|
||||
|
||||
require_once 'Doctrine/Common/ClassLoader.php';
|
||||
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
||||
|
||||
fwrite(
|
||||
STDERR,
|
||||
'[Warning] The use of this script is discouraged. See'
|
||||
. ' https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/tools.html#doctrine-console'
|
||||
. ' for instructions on bootstrapping the console runner.'
|
||||
. PHP_EOL
|
||||
);
|
||||
|
||||
echo PHP_EOL . PHP_EOL;
|
||||
|
||||
$autoloadFiles = [
|
||||
__DIR__ . '/../vendor/autoload.php',
|
||||
__DIR__ . '/../../../autoload.php'
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
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="mysqli"/>
|
||||
<var name="db_host" value="127.0.0.1" />
|
||||
<var name="db_port" value="3306"/>
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
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="pdo_mysql"/>
|
||||
<var name="db_host" value="127.0.0.1" />
|
||||
<var name="db_port" value="3306"/>
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
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="pdo_pgsql"/>
|
||||
<var name="db_host" value="localhost" />
|
||||
<var name="db_user" value="postgres" />
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
|
||||
colors="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
failOnRisky="true"
|
||||
convertDeprecationsToExceptions="true"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
<!-- use an in-memory sqlite database -->
|
||||
<var name="db_driver" value="pdo_sqlite"/>
|
||||
<var name="db_memory" value="true"/>
|
||||
|
||||
@@ -13,36 +13,45 @@
|
||||
{"name": "Marco Pivetta", "email": "ocramius@gmail.com"}
|
||||
],
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 ||^8.0",
|
||||
"php": "^7.1 || ^8.0",
|
||||
"composer-runtime-api": "^2",
|
||||
"ext-ctype": "*",
|
||||
"ext-pdo": "*",
|
||||
"composer/package-versions-deprecated": "^1.8",
|
||||
"doctrine/annotations": "^1.13",
|
||||
"doctrine/cache": "^1.12.1 || ^2.1.1",
|
||||
"doctrine/collections": "^1.5",
|
||||
"doctrine/common": "^3.0.3",
|
||||
"doctrine/dbal": "^2.13.0",
|
||||
"doctrine/deprecations": "^0.5.3",
|
||||
"doctrine/dbal": "^2.13.1 || ^3.2",
|
||||
"doctrine/deprecations": "^0.5.3 || ^1",
|
||||
"doctrine/event-manager": "^1.1",
|
||||
"doctrine/inflector": "^1.4 || ^2.0",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
"doctrine/lexer": "^1.0",
|
||||
"doctrine/persistence": "^2.2",
|
||||
"doctrine/lexer": "^1.2.3",
|
||||
"doctrine/persistence": "^2.4 || ^3",
|
||||
"psr/cache": "^1 || ^2 || ^3",
|
||||
"symfony/console": "^3.0 || ^4.0 || ^5.0 || ^6.0"
|
||||
"symfony/console": "^3.0 || ^4.0 || ^5.0 || ^6.0",
|
||||
"symfony/polyfill-php72": "^1.23",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "^1.13",
|
||||
"doctrine/coding-standard": "^9.0",
|
||||
"phpbench/phpbench": "^0.16.10 || ^1.0",
|
||||
"phpstan/phpstan": "0.12.94",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
|
||||
"squizlabs/php_codesniffer": "3.6.0",
|
||||
"symfony/cache": "^4.4 || ^5.2",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.6.3",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.6.2",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
|
||||
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
|
||||
"vimeo/psalm": "4.7.0"
|
||||
"vimeo/psalm": "4.23.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/annotations": "<1.13 || >= 2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0",
|
||||
|
||||
201
docs/en/conf.py
201
docs/en/conf.py
@@ -1,201 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Doctrine 2 ORM documentation build configuration file, created by
|
||||
# sphinx-quickstart on Fri Dec 3 18:10:24 2010.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os, datetime
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.append(os.path.abspath('_exts'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['configurationblock']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Doctrine 2 ORM'
|
||||
copyright = u'2010-%y, Doctrine Project Team'.format(datetime.date.today)
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '2'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '2'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
language = 'en'
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of documents that shouldn't be included in the build.
|
||||
#unused_docs = []
|
||||
|
||||
# List of directories, relative to source directory, that shouldn't be searched
|
||||
# for source files.
|
||||
exclude_trees = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
show_authors = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
html_theme = 'doctrine'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
html_theme_path = ['_theme']
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_use_modindex = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = ''
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Doctrine2ORMdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'Doctrine2ORM.tex', u'Doctrine 2 ORM Documentation',
|
||||
u'Doctrine Project Team', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_use_modindex = True
|
||||
|
||||
primary_domain = "dcorm"
|
||||
|
||||
def linkcode_resolve(domain, info):
|
||||
if domain == 'dcorm':
|
||||
return 'http://'
|
||||
return None
|
||||
@@ -0,0 +1,74 @@
|
||||
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;
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
@@ -4,7 +4,7 @@ Advanced field value conversion using custom mapping types
|
||||
.. sectionauthor:: Jan Sorgalla <jsorgalla@googlemail.com>
|
||||
|
||||
When creating entities, you sometimes have the need to transform field values
|
||||
before they are saved to the database. In Doctrine you can use Custom Mapping
|
||||
before they are saved to the database. In Doctrine you can use Custom Mapping
|
||||
Types to solve this (see: :ref:`reference-basic-mapping-custom-mapping-types`).
|
||||
|
||||
There are several ways to achieve this: converting the value inside the Type
|
||||
@@ -15,7 +15,7 @@ type `Point <https://dev.mysql.com/doc/refman/8.0/en/gis-class-point.html>`_.
|
||||
|
||||
The ``Point`` type is part of the `Spatial extension <https://dev.mysql.com/doc/refman/8.0/en/spatial-extensions.html>`_
|
||||
of MySQL and enables you to store a single location in a coordinate space by
|
||||
using x and y coordinates. You can use the Point type to store a
|
||||
using x and y coordinates. You can use the Point type to store a
|
||||
longitude/latitude pair to represent a geographic location.
|
||||
|
||||
The entity
|
||||
@@ -29,9 +29,9 @@ The entity class:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
|
||||
namespace Geo\Entity;
|
||||
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
@@ -84,7 +84,7 @@ The entity class:
|
||||
}
|
||||
}
|
||||
|
||||
We use the custom type ``point`` in the ``@Column`` docblock annotation of the
|
||||
We use the custom type ``point`` in the ``@Column`` docblock annotation of the
|
||||
``$point`` field. We will create this custom mapping type in the next chapter.
|
||||
|
||||
The point class:
|
||||
@@ -92,7 +92,7 @@ The point class:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
|
||||
namespace Geo\ValueObject;
|
||||
|
||||
class Point
|
||||
@@ -196,7 +196,7 @@ The format of the string representation format is called
|
||||
`Well-known text (WKT) <https://en.wikipedia.org/wiki/Well-known_text>`_.
|
||||
The advantage of this format is, that it is both human readable and parsable by MySQL.
|
||||
|
||||
Internally, MySQL stores geometry values in a binary format that is not
|
||||
Internally, MySQL stores geometry values in a binary format that is not
|
||||
identical to the WKT format. So, we need to let MySQL transform the WKT
|
||||
representation into its internal format.
|
||||
|
||||
@@ -210,13 +210,13 @@ which convert WKT strings to and from the internal format of MySQL.
|
||||
|
||||
.. note::
|
||||
|
||||
When using DQL queries, the ``convertToPHPValueSQL`` and
|
||||
When using DQL queries, the ``convertToPHPValueSQL`` and
|
||||
``convertToDatabaseValueSQL`` methods only apply to identification variables
|
||||
and path expressions in SELECT clauses. Expressions in WHERE clauses are
|
||||
and path expressions in SELECT clauses. Expressions in WHERE clauses are
|
||||
**not** wrapped!
|
||||
|
||||
If you want to use Point values in WHERE clauses, you have to implement a
|
||||
:doc:`user defined function <dql-user-defined-functions>` for
|
||||
:doc:`user defined function <dql-user-defined-functions>` for
|
||||
``PointFromText``.
|
||||
|
||||
Example usage
|
||||
@@ -252,5 +252,5 @@ Example usage
|
||||
$query = $em->createQuery("SELECT l FROM Geo\Entity\Location l WHERE l.address = '1600 Amphitheatre Parkway, Mountain View, CA'");
|
||||
$location = $query->getSingleResult();
|
||||
|
||||
/* @var Geo\ValueObject\Point */
|
||||
/** @var Geo\ValueObject\Point */
|
||||
$point = $location->getPoint();
|
||||
|
||||
@@ -33,8 +33,8 @@ the DQL parser:
|
||||
is only ever one of them. We implemented the default SqlWalker
|
||||
implementation for it.
|
||||
- A tree walker. There can be many tree walkers, they cannot
|
||||
generate the sql, however they can modify the AST before its
|
||||
rendered to sql.
|
||||
generate the SQL, however they can modify the AST before its
|
||||
rendered to SQL.
|
||||
|
||||
Now this is all awfully technical, so let me come to some use-cases
|
||||
fast to keep you motivated. Using walker implementation you can for
|
||||
@@ -50,7 +50,7 @@ example:
|
||||
- Modify the Output walker to pretty print the SQL for debugging
|
||||
purposes.
|
||||
|
||||
In this cookbook-entry I will show examples on the first two
|
||||
In this cookbook-entry I will show examples of the first two
|
||||
points. There are probably much more use-cases.
|
||||
|
||||
Generic count query for pagination
|
||||
@@ -64,7 +64,7 @@ like:
|
||||
|
||||
SELECT p, c, a FROM BlogPost p JOIN p.category c JOIN p.author a WHERE ...
|
||||
|
||||
Now in this query the blog post is the root entity, meaning its the
|
||||
Now in this query the blog post is the root entity, meaning it's the
|
||||
one that is hydrated directly from the query and returned as an
|
||||
array of blog posts. In contrast the comment and author are loaded
|
||||
for deeper use in the object tree.
|
||||
@@ -79,7 +79,7 @@ query for pagination would look like:
|
||||
SELECT count(DISTINCT p.id) FROM BlogPost p JOIN p.category c JOIN p.author a WHERE ...
|
||||
|
||||
Now you could go and write each of these queries by hand, or you
|
||||
can use a tree walker to modify the AST for you. Lets see how the
|
||||
can use a tree walker to modify the AST for you. Let's see how the
|
||||
API would look for this use-case:
|
||||
|
||||
.. code-block:: php
|
||||
@@ -88,7 +88,7 @@ API would look for this use-case:
|
||||
$pageNum = 1;
|
||||
$query = $em->createQuery($dql);
|
||||
$query->setFirstResult( ($pageNum-1) * 20)->setMaxResults(20);
|
||||
|
||||
|
||||
$totalResults = Paginate::count($query);
|
||||
$results = $query->getResult();
|
||||
|
||||
@@ -101,12 +101,12 @@ The ``Paginate::count(Query $query)`` looks like:
|
||||
{
|
||||
static public function count(Query $query)
|
||||
{
|
||||
/* @var $countQuery Query */
|
||||
/** @var Query $countQuery */
|
||||
$countQuery = clone $query;
|
||||
|
||||
|
||||
$countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('DoctrineExtensions\Paginate\CountSqlWalker'));
|
||||
$countQuery->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
|
||||
return $countQuery->getSingleScalarResult();
|
||||
}
|
||||
}
|
||||
@@ -137,13 +137,13 @@ implementation is:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$pathExpression = new PathExpression(
|
||||
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $parentName,
|
||||
$parent['metadata']->getSingleIdentifierFieldName()
|
||||
);
|
||||
$pathExpression->type = PathExpression::TYPE_STATE_FIELD;
|
||||
|
||||
|
||||
$AST->selectClause->selectExpressions = array(
|
||||
new SelectExpression(
|
||||
new AggregateExpression('count', $pathExpression, true), null
|
||||
@@ -196,7 +196,7 @@ modify the generation of the SELECT clause, adding the
|
||||
public function walkSelectClause($selectClause)
|
||||
{
|
||||
$sql = parent::walkSelectClause($selectClause);
|
||||
|
||||
|
||||
if ($this->getQuery()->getHint('mysqlWalker.sqlNoCache') === true) {
|
||||
if ($selectClause->isDistinct) {
|
||||
$sql = str_replace('SELECT DISTINCT', 'SELECT DISTINCT SQL_NO_CACHE', $sql);
|
||||
@@ -204,7 +204,7 @@ modify the generation of the SELECT clause, adding the
|
||||
$sql = str_replace('SELECT', 'SELECT SQL_NO_CACHE', $sql);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ configuration:
|
||||
$config->addCustomStringFunction($name, $class);
|
||||
$config->addCustomNumericFunction($name, $class);
|
||||
$config->addCustomDatetimeFunction($name, $class);
|
||||
|
||||
|
||||
$em = EntityManager::create($dbParams, $config);
|
||||
|
||||
The ``$name`` is the name the function will be referred to in the
|
||||
@@ -96,7 +96,7 @@ discuss it step by step:
|
||||
// (1)
|
||||
public $firstDateExpression = null;
|
||||
public $secondDateExpression = null;
|
||||
|
||||
|
||||
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER); // (2)
|
||||
@@ -106,7 +106,7 @@ discuss it step by step:
|
||||
$this->secondDateExpression = $parser->ArithmeticPrimary(); // (6)
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS); // (3)
|
||||
}
|
||||
|
||||
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
{
|
||||
return 'DATEDIFF(' .
|
||||
@@ -131,8 +131,8 @@ generation of a DateDiff FunctionNode somewhere in the AST of the
|
||||
dql statement.
|
||||
|
||||
The ``ArithmeticPrimary`` method call is the most common
|
||||
denominator of valid EBNF tokens taken from the
|
||||
`DQL EBNF grammar <https://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#ebnf>`_
|
||||
denominator of valid EBNF tokens taken from the :ref:`DQL EBNF grammar
|
||||
<dql_ebnf_grammar>`
|
||||
that matches our requirements for valid input into the DateDiff Dql
|
||||
function. Picking the right tokens for your methods is a tricky
|
||||
business, but the EBNF grammar is pretty helpful finding it, as is
|
||||
@@ -180,28 +180,28 @@ I'll skip the blah and show the code for this function:
|
||||
public $firstDateExpression = null;
|
||||
public $intervalExpression = null;
|
||||
public $unit = null;
|
||||
|
||||
|
||||
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
|
||||
$this->firstDateExpression = $parser->ArithmeticPrimary();
|
||||
|
||||
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
|
||||
|
||||
$this->intervalExpression = $parser->ArithmeticPrimary();
|
||||
|
||||
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
|
||||
/* @var $lexer Lexer */
|
||||
|
||||
/** @var Lexer $lexer */
|
||||
$lexer = $parser->getLexer();
|
||||
$this->unit = $lexer->token['value'];
|
||||
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
|
||||
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
{
|
||||
return 'DATE_ADD(' .
|
||||
|
||||
@@ -3,8 +3,8 @@ Implementing Wakeup or Clone
|
||||
|
||||
.. sectionauthor:: Roman Borschel (roman@code-factory.org)
|
||||
|
||||
As explained in the
|
||||
`restrictions for entity classes in the manual <https://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/architecture.html#entities>`_,
|
||||
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
|
||||
|
||||
@@ -47,7 +47,7 @@ appropriate autoloaders.
|
||||
}
|
||||
|
||||
foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) {
|
||||
if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadataInfo::MANY_TO_MANY && $mapping['isOwningSide']) {
|
||||
if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadata::MANY_TO_MANY && $mapping['isOwningSide']) {
|
||||
$mappedTableName = $mapping['joinTable']['name'];
|
||||
$classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ Doctrine ORM don't panic. You can get help from different sources:
|
||||
- The `Doctrine Mailing List <https://groups.google.com/group/doctrine-user>`_
|
||||
- Slack chat room `#orm <https://www.doctrine-project.org/slack>`_
|
||||
- Report a bug on `GitHub <https://github.com/doctrine/orm/issues>`_.
|
||||
- On `Twitter <https://twitter.com/search/%23doctrine2>`_ with ``#doctrine2``
|
||||
- On `StackOverflow <https://stackoverflow.com/questions/tagged/doctrine-orm>`_
|
||||
|
||||
If you need more structure over the different topics you can browse the :doc:`table
|
||||
|
||||
@@ -9,22 +9,28 @@ steps of configuration.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\EntityManager,
|
||||
Doctrine\ORM\Configuration;
|
||||
|
||||
use Doctrine\ORM\Configuration;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\ORMSetup;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
|
||||
|
||||
// ...
|
||||
|
||||
if ($applicationMode == "development") {
|
||||
$cache = new \Doctrine\Common\Cache\ArrayCache;
|
||||
$queryCache = new ArrayAdapter();
|
||||
$metadataCache = new ArrayAdapter();
|
||||
} else {
|
||||
$cache = new \Doctrine\Common\Cache\ApcCache;
|
||||
$queryCache = new PhpFilesAdapter('doctrine_queries');
|
||||
$metadataCache = new PhpFilesAdapter('doctrine_metadata');
|
||||
}
|
||||
|
||||
$config = new Configuration;
|
||||
$config->setMetadataCacheImpl($cache);
|
||||
$driverImpl = $config->newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
|
||||
$config->setMetadataCache($metadataCache);
|
||||
$driverImpl = ORMSetup::createDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
$config->setQueryCacheImpl($cache);
|
||||
$config->setQueryCache($queryCache);
|
||||
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
|
||||
$config->setProxyNamespace('MyProject\Proxies');
|
||||
|
||||
@@ -41,19 +47,22 @@ steps of configuration.
|
||||
|
||||
$em = EntityManager::create($connectionOptions, $config);
|
||||
|
||||
Doctrine and Caching
|
||||
--------------------
|
||||
|
||||
Doctrine is optimized for working with caches. The main parts in Doctrine
|
||||
that are optimized for caching are the metadata mapping information with
|
||||
the metadata cache and the DQL to SQL conversions with the query cache.
|
||||
These 2 caches require only an absolute minimum of memory yet they heavily
|
||||
improve the runtime performance of Doctrine.
|
||||
|
||||
Doctrine does not bundle its own cache implementation anymore. Instead,
|
||||
the PSR-6 standard interfaces are used to access the cache. In the examples
|
||||
in this documentation, Symfony Cache is used as a reference implementation.
|
||||
|
||||
.. note::
|
||||
|
||||
Do not use Doctrine without a metadata and query cache!
|
||||
Doctrine is optimized for working with caches. The main
|
||||
parts in Doctrine that are optimized for caching are the metadata
|
||||
mapping information with the metadata cache and the DQL to SQL
|
||||
conversions with the query cache. These 2 caches require only an
|
||||
absolute minimum of memory yet they heavily improve the runtime
|
||||
performance of Doctrine. The recommended cache driver to use with
|
||||
Doctrine is `APC <https://php.net/apc>`_. APC provides you with
|
||||
an opcode-cache (which is highly recommended anyway) and a very
|
||||
fast in-memory cache storage that you can use for the metadata and
|
||||
query caches as seen in the previous code snippet.
|
||||
|
||||
Configuration Options
|
||||
---------------------
|
||||
@@ -121,7 +130,9 @@ the ``Doctrine\ORM\Configuration``:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$driverImpl = $config->newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
|
||||
use Doctrine\ORM\ORMSetup;
|
||||
|
||||
$driverImpl = ORMSetup::createDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
|
||||
$config->setMetadataDriverImpl($driverImpl);
|
||||
|
||||
The path information to the entities is required for the annotation
|
||||
@@ -137,30 +148,21 @@ Metadata Cache (***RECOMMENDED***)
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$config->setMetadataCacheImpl($cache);
|
||||
$config->getMetadataCacheImpl();
|
||||
$config->setMetadataCache($cache);
|
||||
$config->getMetadataCache();
|
||||
|
||||
Gets or sets the cache implementation to use for caching metadata
|
||||
Gets or sets the cache adapter to use for caching metadata
|
||||
information, that is, all the information you supply via
|
||||
annotations, xml or yaml, so that they do not need to be parsed and
|
||||
loaded from scratch on every single request which is a waste of
|
||||
resources. The cache implementation must implement the
|
||||
``Doctrine\Common\Cache\Cache`` interface.
|
||||
resources. The cache implementation must implement the PSR-6
|
||||
``Psr\Cache\CacheItemPoolInterface`` interface.
|
||||
|
||||
Usage of a metadata cache is highly recommended.
|
||||
|
||||
The recommended implementations for production are:
|
||||
|
||||
|
||||
- ``Doctrine\Common\Cache\ApcCache``
|
||||
- ``Doctrine\Common\Cache\ApcuCache``
|
||||
- ``Doctrine\Common\Cache\MemcacheCache``
|
||||
- ``Doctrine\Common\Cache\XcacheCache``
|
||||
- ``Doctrine\Common\Cache\RedisCache``
|
||||
|
||||
For development you should use the
|
||||
``Doctrine\Common\Cache\ArrayCache`` which only caches data on a
|
||||
per-request basis.
|
||||
For development you should use an array cache like
|
||||
``Symfony\Component\Cache\Adapter\ArrayAdapter``
|
||||
which only caches data on a per-request basis.
|
||||
|
||||
Query Cache (***RECOMMENDED***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -168,8 +170,8 @@ Query Cache (***RECOMMENDED***)
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$config->setQueryCacheImpl($cache);
|
||||
$config->getQueryCacheImpl();
|
||||
$config->setQueryCache($cache);
|
||||
$config->getQueryCache();
|
||||
|
||||
Gets or sets the cache implementation to use for caching DQL
|
||||
queries, that is, the result of a DQL parsing process that includes
|
||||
@@ -181,18 +183,9 @@ minimal memory usage in your cache).
|
||||
|
||||
Usage of a query cache is highly recommended.
|
||||
|
||||
The recommended implementations for production are:
|
||||
|
||||
|
||||
- ``Doctrine\Common\Cache\ApcCache``
|
||||
- ``Doctrine\Common\Cache\ApcuCache``
|
||||
- ``Doctrine\Common\Cache\MemcacheCache``
|
||||
- ``Doctrine\Common\Cache\XcacheCache``
|
||||
- ``Doctrine\Common\Cache\RedisCache``
|
||||
|
||||
For development you should use the
|
||||
``Doctrine\Common\Cache\ArrayCache`` which only caches data on a
|
||||
per-request basis.
|
||||
For development you should use an array cache like
|
||||
``Symfony\Component\Cache\Adapter\ArrayAdapter``
|
||||
which only caches data on a per-request basis.
|
||||
|
||||
SQL Logger (***Optional***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -205,10 +198,7 @@ SQL Logger (***Optional***)
|
||||
|
||||
Gets or sets the logger to use for logging all SQL statements
|
||||
executed by Doctrine. The logger class must implement the
|
||||
``Doctrine\DBAL\Logging\SQLLogger`` interface. A simple default
|
||||
implementation that logs to the standard output using ``echo`` and
|
||||
``var_dump`` can be found at
|
||||
``Doctrine\DBAL\Logging\EchoSQLLogger``.
|
||||
deprecated ``Doctrine\DBAL\Logging\SQLLogger`` interface.
|
||||
|
||||
Auto-generating Proxy Classes (***OPTIONAL***)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -269,10 +259,10 @@ Development vs Production Configuration
|
||||
|
||||
You should code your Doctrine2 bootstrapping with two different
|
||||
runtime models in mind. There are some serious benefits of using
|
||||
APC or Memcache in production. In development however this will
|
||||
APCu or Memcache in production. In development however this will
|
||||
frequently give you fatal errors, when you change your entities and
|
||||
the cache still keeps the outdated metadata. That is why we
|
||||
recommend the ``ArrayCache`` for development.
|
||||
recommend an array cache for development.
|
||||
|
||||
Furthermore you should have the Auto-generating Proxy Classes
|
||||
option to true in development and to false in production. If this
|
||||
@@ -450,22 +440,22 @@ That will be available for all entities without a custom repository class.
|
||||
The default value is ``Doctrine\ORM\EntityRepository``.
|
||||
Any repository class must be a subclass of EntityRepository otherwise you got an ORMException
|
||||
|
||||
Setting up the Console
|
||||
----------------------
|
||||
Ignoring entities (***OPTIONAL***)
|
||||
-----------------------------------
|
||||
|
||||
Doctrine uses the Symfony Console component for generating the command
|
||||
line interface. You can take a look at the ``vendor/bin/doctrine.php``
|
||||
script and the ``Doctrine\ORM\Tools\Console\ConsoleRunner`` command
|
||||
for inspiration how to setup the cli.
|
||||
|
||||
In general the required code looks like this:
|
||||
Specifies the Entity FQCNs to ignore.
|
||||
SchemaTool will then skip these (e.g. when comparing schemas).
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cli = new Application('Doctrine Command Line Interface', \Doctrine\ORM\Version::VERSION);
|
||||
$cli->setCatchExceptions(true);
|
||||
$cli->setHelperSet($helperSet);
|
||||
Doctrine\ORM\Tools\Console\ConsoleRunner::addCommands($cli);
|
||||
$cli->run();
|
||||
$config->setSchemaIgnoreClasses([$fqcn]);
|
||||
$config->getSchemaIgnoreClasses();
|
||||
|
||||
|
||||
Setting up the Console
|
||||
----------------------
|
||||
|
||||
Doctrine uses the Symfony Console component for generating the command
|
||||
line interface. You can take a look at the
|
||||
:doc:`tools chapter <../reference/tools>` for inspiration how to setup the cli.
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
Annotations Reference
|
||||
=====================
|
||||
|
||||
.. note::
|
||||
|
||||
To be able to use annotations, you will have to install an extra
|
||||
package called ``doctrine/annotations``.
|
||||
|
||||
You've probably used docblock annotations in some form already,
|
||||
most likely to provide documentation metadata for a tool like
|
||||
``PHPDocumentor`` (@author, @link, ...). Docblock annotations are a
|
||||
@@ -13,12 +18,15 @@ chances of clashes with other docblock annotations, the Doctrine ORM
|
||||
docblock annotations feature an alternative syntax that is heavily
|
||||
inspired by the Annotation syntax introduced in Java 5.
|
||||
|
||||
The implementation of these enhanced docblock annotations is
|
||||
located in the ``Doctrine\Common\Annotations`` namespace and
|
||||
therefore part of the Common package. Doctrine ORM docblock
|
||||
annotations support namespaces and nested annotations among other
|
||||
things. The Doctrine ORM ORM defines its own set of docblock
|
||||
annotations for supplying object-relational mapping metadata.
|
||||
The implementation of these enhanced docblock annotations is located in
|
||||
the ``doctrine/annotations`` package, but in the
|
||||
``Doctrine\Common\Annotations`` namespace for backwards compatibility
|
||||
reasons. Note that ``doctrine/annotations`` is not required by Doctrine
|
||||
ORM, and you will need to require that package if you want to use
|
||||
annotations. Doctrine ORM docblock annotations support namespaces and
|
||||
nested annotations among other things. The Doctrine ORM defines its
|
||||
own set of docblock annotations for supplying object-relational mapping
|
||||
metadata.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -115,6 +123,18 @@ 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.
|
||||
If not specified, default value is true.
|
||||
|
||||
- **updatable**: Boolean value to determine if the column should be
|
||||
included when updating the row of the underlying entities table.
|
||||
If not specified, default value is true.
|
||||
|
||||
- **generated**: An enum with the possible values ALWAYS, INSERT, NEVER. Is
|
||||
used after an INSERT or UPDATE statement to determine if the database
|
||||
generated this value and it needs to be fetched using a SELECT statement.
|
||||
|
||||
- **options**: Array of additional options:
|
||||
|
||||
- ``default``: The default value to set for the column if no value
|
||||
@@ -185,6 +205,13 @@ Examples:
|
||||
*/
|
||||
protected $loginCount;
|
||||
|
||||
/**
|
||||
* Generated column
|
||||
* @Column(type="string", name="user_fullname", insertable=false, updatable=false)
|
||||
* MySQL example: full_name char(41) GENERATED ALWAYS AS (concat(firstname,' ',lastname)),
|
||||
*/
|
||||
protected $fullname;
|
||||
|
||||
.. _annref_column_result:
|
||||
|
||||
@ColumnResult
|
||||
@@ -455,7 +482,7 @@ Optional attributes:
|
||||
|
||||
|
||||
- **strategy**: Set the name of the identifier generation strategy.
|
||||
Valid values are ``AUTO``, ``SEQUENCE``, ``TABLE``, ``IDENTITY``, ``UUID``, ``CUSTOM`` and ``NONE``, explained
|
||||
Valid values are ``AUTO``, ``SEQUENCE``, ``IDENTITY``, ``UUID`` (deprecated), ``CUSTOM`` and ``NONE``, explained
|
||||
in the :ref:`Identifier Generation Strategies <identifier-generation-strategies>` section.
|
||||
If not specified, default value is AUTO.
|
||||
|
||||
|
||||
@@ -66,6 +66,8 @@ The root namespace of the ORM package is ``Doctrine\ORM``.
|
||||
Terminology
|
||||
-----------
|
||||
|
||||
.. _terminology_entities:
|
||||
|
||||
Entities
|
||||
~~~~~~~~
|
||||
|
||||
@@ -82,9 +84,13 @@ be any regular PHP class observing the following restrictions:
|
||||
: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>`.
|
||||
Also consider implementing
|
||||
`Serializable <https://php.net/manual/en/class.serializable.php>`_
|
||||
instead.
|
||||
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.
|
||||
- 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
|
||||
@@ -93,6 +99,7 @@ be any regular PHP class observing the following restrictions:
|
||||
- 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
|
||||
@@ -161,7 +168,8 @@ 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).
|
||||
did not find a way yet, if you did, please contact us). The
|
||||
``Serializable`` interface is also deprecated beginning with PHP 8.1.
|
||||
|
||||
The EntityManager
|
||||
~~~~~~~~~~~~~~~~~
|
||||
@@ -184,6 +192,8 @@ in well defined units of work. Work with your objects and modify
|
||||
them as usual and when you're done call ``EntityManager#flush()``
|
||||
to make your changes persistent.
|
||||
|
||||
.. _unit-of-work:
|
||||
|
||||
The Unit of Work
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -430,7 +430,7 @@ The following example sets up such a unidirectional one-to-many association:
|
||||
// ...
|
||||
|
||||
/**
|
||||
* Many User have Many Phonenumbers.
|
||||
* Many Users have Many Phonenumbers.
|
||||
* @ManyToMany(targetEntity="Phonenumber")
|
||||
* @JoinTable(name="users_phonenumbers",
|
||||
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
|
||||
|
||||
@@ -10,6 +10,8 @@ annotation metadata supported since the first version 2.0.
|
||||
Index
|
||||
-----
|
||||
|
||||
- :ref:`#[AssociationOverride] <attrref_associationoverride]`
|
||||
- :ref:`#[AttributeOverride] <attrref_attributeoverride]`
|
||||
- :ref:`#[Column] <attrref_column>`
|
||||
- :ref:`#[Cache] <attrref_cache>`
|
||||
- :ref:`#[ChangeTrackingPolicy <attrref_changetrackingpolicy>`
|
||||
@@ -49,6 +51,93 @@ Index
|
||||
Reference
|
||||
---------
|
||||
|
||||
.. _attrref_associationoverride:
|
||||
|
||||
#[AssociationOverride]
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In an inheritance hierarchy this attribute allows to override the
|
||||
assocation mapping definitions of the parent mappings. It needs to be nested
|
||||
within a ``#[AssociationOverrides]`` on the class level.
|
||||
|
||||
Required parameters:
|
||||
|
||||
- **name**: Name of the association mapping to overwrite.
|
||||
|
||||
Optional parameters:
|
||||
|
||||
- **joinColumns**: A list of nested ``#[JoinColumn]`` declarations.
|
||||
- **joinTable**: A nested ``#[JoinTable]`` declaration in case of a many-to-many overwrite.
|
||||
- **inversedBy**: The name of the inversedBy field on the target entity side.
|
||||
- **fetch**: The fetch strategy, one of: EAGER, LAZY, EXTRA_LAZY.
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\AssociationOverride;
|
||||
use Doctrine\ORM\Mapping\AssociationOverrides;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
|
||||
#[AssociationOverrides([
|
||||
new AssociationOverride(
|
||||
name: "groups",
|
||||
joinTable: new JoinTable(
|
||||
name: "ddc964_users_admingroups",
|
||||
),
|
||||
joinColumns: [new JoinColumn(name: "adminuser_id")],
|
||||
inverseJoinColumns: [new JoinColumn(name: "admingroup_id")]
|
||||
),
|
||||
new AssociationOverride(
|
||||
name: "address",
|
||||
joinColumns: [new JoinColumn(name: "adminaddress_id", referencedColumnName: "id")]
|
||||
)
|
||||
])]
|
||||
class DDC964Admin extends DDC964User
|
||||
{
|
||||
}
|
||||
|
||||
.. _attrref_attributeoverride:
|
||||
|
||||
#[AttributeOverride]
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In an inheritance hierarchy this attribute allows to override the
|
||||
field mapping definitions of the parent mappings. It needs to be nested
|
||||
within a ``#[AttributeOverrides]`` on the class level.
|
||||
|
||||
Required parameters:
|
||||
|
||||
- **name**: Name of the association mapping to overwrite.
|
||||
- **column**: A nested ``#[Column]`` attribute with the overwritten field settings.
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\AttributeOverride;
|
||||
use Doctrine\ORM\Mapping\AttributeOverrides;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
|
||||
#[Entity]
|
||||
#[AttributeOverrides([
|
||||
new AttributeOverride(
|
||||
name: "id",
|
||||
column: new Column(name: "guest_id", type: "integer", length: 140)
|
||||
),
|
||||
new AttributeOverride(
|
||||
name: "name",
|
||||
column: new Column(name: "guest_name", nullable: false, unique: true, length: 240)
|
||||
)]
|
||||
)]
|
||||
class DDC964Guest extends DDC964User
|
||||
{
|
||||
}
|
||||
|
||||
.. _attrref_column:
|
||||
|
||||
#[Column]
|
||||
@@ -59,12 +148,12 @@ inside the instance variables PHP DocBlock comment. Any value hold
|
||||
inside this variable will be saved to and loaded from the database
|
||||
as part of the lifecycle of the instance variables entity-class.
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
- **type**: Name of the DBAL Type which does the conversion between PHP
|
||||
and Database representation.
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **name**: By default the property name is used for the database
|
||||
column name also, however the ``name`` attribute allows you to
|
||||
@@ -89,6 +178,18 @@ 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.
|
||||
If not specified, default value is true.
|
||||
|
||||
- **updatable**: Boolean value to determine if the column should be
|
||||
included when updating the row of the underlying entities table.
|
||||
If not specified, default value is true.
|
||||
|
||||
- **generated**: An enum with the possible values ALWAYS, INSERT, NEVER. Is
|
||||
used after an INSERT or UPDATE statement to determine if the database
|
||||
generated this value and it needs to be fetched using a SELECT statement.
|
||||
|
||||
- **options**: Array of additional options:
|
||||
|
||||
- ``default``: The default value to set for the column if no value
|
||||
@@ -159,13 +260,22 @@ Examples:
|
||||
)]
|
||||
protected $loginCount;
|
||||
|
||||
// MySQL example: full_name char(41) GENERATED ALWAYS AS (concat(firstname,' ',lastname)),
|
||||
#[Column(
|
||||
type: "string",
|
||||
name: "user_fullname",
|
||||
insertable: false,
|
||||
updatable: false
|
||||
)]
|
||||
protected $fullname;
|
||||
|
||||
.. _attrref_cache:
|
||||
|
||||
#[Cache]
|
||||
~~~~~~~~
|
||||
Add caching strategy to a root entity or a collection.
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **usage**: One of ``READ_ONLY``, ``READ_WRITE`` or ``NONSTRICT_READ_WRITE``, By default this is ``READ_ONLY``.
|
||||
- **region**: An specific region name
|
||||
@@ -210,7 +320,7 @@ Example:
|
||||
|
||||
This attribute allows you to specify a user-provided class to generate identifiers. This attribute only works when both :ref:`#[Id] <attrref_id>` and :ref:`#[GeneratedValue(strategy: "CUSTOM")] <attrref_generatedvalue>` are specified.
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
- **class**: name of the class which should extend Doctrine\ORM\Id\AbstractIdGenerator
|
||||
|
||||
@@ -244,13 +354,13 @@ actually instantiated as.
|
||||
If this attribute is not specified, the discriminator column defaults
|
||||
to a string column of length 255 called ``dtype``.
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
|
||||
- **name**: The column name of the discriminator. This name is also
|
||||
used during Array hydration as key to specify the class-name.
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
|
||||
- **type**: By default this is string.
|
||||
@@ -319,7 +429,7 @@ attribute to establish the relationship between the two classes.
|
||||
The embedded attribute is required on an entity's member variable,
|
||||
in order to specify that it is an embedded class.
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
- **class**: The embeddable class
|
||||
|
||||
@@ -331,7 +441,7 @@ Required attributes:
|
||||
Required attribute to mark a PHP class as an entity. Doctrine manages
|
||||
the persistence of all classes marked as entities.
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **repositoryClass**: Specifies the FQCN of a subclass of the
|
||||
``EntityRepository``. Use of repositories for entities is encouraged to keep
|
||||
@@ -368,11 +478,11 @@ conjunction with #[Id].
|
||||
If this attribute is not specified with ``#[Id]`` the ``NONE`` strategy is
|
||||
used as default.
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **strategy**: Set the name of the identifier generation strategy.
|
||||
Valid values are ``AUTO``, ``SEQUENCE``, ``TABLE``, ``IDENTITY``,
|
||||
``UUID``, ``CUSTOM`` and ``NONE``.
|
||||
Valid values are ``AUTO``, ``SEQUENCE``, ``IDENTITY``, ``UUID``
|
||||
(deprecated), ``CUSTOM`` and ``NONE``.
|
||||
If not specified, the default value is ``AUTO``.
|
||||
|
||||
Example:
|
||||
@@ -424,14 +534,14 @@ Attribute is used on the entity-class level. It provides a hint to the SchemaToo
|
||||
generate a database index on the specified table columns. It only
|
||||
has meaning in the ``SchemaTool`` schema generation context.
|
||||
|
||||
Required attributes:
|
||||
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 attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
@@ -460,7 +570,7 @@ Example with partial indexes:
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Index;
|
||||
|
||||
#[Index(name: "search_idx", columns: {"category"},
|
||||
#[Index(name: "search_idx", columns: ["category"],
|
||||
options: [
|
||||
"where": "((category IS NOT NULL))"
|
||||
]
|
||||
@@ -518,7 +628,7 @@ Examples:
|
||||
#[Entity]
|
||||
#[InheritanceType("SINGLE_TABLE")]
|
||||
#[DiscriminatorColumn(name: "discr", type: "string")]
|
||||
#[DiscriminatorMap({"person" = "Person", "employee" = "Employee"})]
|
||||
#[DiscriminatorMap(["person" => "Person", "employee" => "Employee"])]
|
||||
class Person
|
||||
{
|
||||
// ...
|
||||
@@ -527,7 +637,7 @@ Examples:
|
||||
#[Entity]
|
||||
#[InheritanceType("JOINED")]
|
||||
#[DiscriminatorColumn(name: "discr", type: "string")]
|
||||
#[DiscriminatorMap({"person" = "Person", "employee" = "Employee"})]
|
||||
#[DiscriminatorMap(["person" => "Person", "employee" => "Employee"])]
|
||||
class Person
|
||||
{
|
||||
// ...
|
||||
@@ -546,9 +656,10 @@ are missing they will be computed considering the field's name and the current
|
||||
|
||||
The ``#[InverseJoinColumn]`` is the same as ``#[JoinColumn]`` and is used in the context
|
||||
of a ``#[ManyToMany]`` attribute declaration to specifiy the details of the join table's
|
||||
column information used for the join to the inverse entity.
|
||||
column information used for the join to the inverse entity. This is only required
|
||||
on PHP 8.0, where nested attributes are not yet supported.
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **name**: Column name that holds the foreign key identifier for
|
||||
this relation. In the context of ``#[JoinTable]`` it specifies the column
|
||||
@@ -596,7 +707,7 @@ details of the database join table. If you do not specify
|
||||
using the affected table and the column names.
|
||||
|
||||
A notable difference to the annotation metadata support, ``#[JoinColumn]``
|
||||
and ``#[InverseJoinColumn]`` are specified at the property level and are not
|
||||
and ``#[InverseJoinColumn]`` can be specified at the property level and are not
|
||||
nested within the ``#[JoinTable]`` attribute.
|
||||
|
||||
Required attribute:
|
||||
@@ -623,14 +734,14 @@ Example:
|
||||
Defines that the annotated instance variable holds a reference that
|
||||
describes a many-to-one relationship between two entities.
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
|
||||
- **targetEntity**: FQCN of the referenced target entity. Can be the
|
||||
unqualified class name if both classes are in the same namespace.
|
||||
*IMPORTANT:* No leading backslash!
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
|
||||
- **cascade**: Cascade Option
|
||||
@@ -659,14 +770,14 @@ additional, optional attribute that has reasonable default
|
||||
configuration values using the table and names of the two related
|
||||
entities.
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
|
||||
- **targetEntity**: FQCN of the referenced target entity. Can be the
|
||||
unqualified class name if both classes are in the same namespace.
|
||||
*IMPORTANT:* No leading backslash!
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
|
||||
- **mappedBy**: This option specifies the property name on the
|
||||
@@ -720,7 +831,7 @@ The ``#[MappedSuperclass]`` attribute cannot be used in conjunction with
|
||||
``#[Entity]``. See the Inheritance Mapping section for
|
||||
:doc:`more details on the restrictions of mapped superclasses <inheritance-mapping>`.
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **repositoryClass**: Specifies the FQCN of a subclass of the EntityRepository.
|
||||
That will be inherited for all subclasses of that Mapped Superclass.
|
||||
@@ -756,13 +867,13 @@ be specified. When no
|
||||
:ref:`#[JoinColumn] <attrref_joincolumn>` is specified it defaults to using the target entity table and
|
||||
primary key column names and the current naming strategy to determine a name for the join column.
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
- **targetEntity**: FQCN of the referenced target entity. Can be the
|
||||
unqualified class name if both classes are in the same namespace.
|
||||
*IMPORTANT:* No leading backslash!
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **cascade**: Cascade Option
|
||||
- **fetch**: One of LAZY or EAGER
|
||||
@@ -786,13 +897,13 @@ Example:
|
||||
#[OneToMany]
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
- **targetEntity**: FQCN of the referenced target entity. Can be the
|
||||
unqualified class name if both classes are in the same namespace.
|
||||
*IMPORTANT:* No leading backslash!
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **cascade**: Cascade Option
|
||||
- **orphanRemoval**: Boolean that specifies if orphans, inverse
|
||||
@@ -916,11 +1027,11 @@ For use with ``#[GeneratedValue(strategy: "SEQUENCE")]`` this
|
||||
attribute allows to specify details about the sequence, such as
|
||||
the increment size and initial values of the sequence.
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
- **sequenceName**: Name of the sequence
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **allocationSize**: Increment the sequence by the allocation size
|
||||
when its fetched. A value larger than 1 allows optimization for
|
||||
@@ -954,11 +1065,11 @@ placed on the entity-class level and is optional. If it is
|
||||
not specified the table name will default to the entity's
|
||||
unqualified classname.
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
- **name**: Name of the table
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **schema**: Name of the schema the table lies in.
|
||||
|
||||
@@ -985,12 +1096,12 @@ generate a database unique constraint on the specified table
|
||||
columns. It only has meaning in the SchemaTool schema generation
|
||||
context.
|
||||
|
||||
Required attributes:
|
||||
Required parameters:
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **columns**: Array of columns.
|
||||
|
||||
Optional attributes:
|
||||
Optional parameters:
|
||||
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
|
||||
@@ -14,17 +14,11 @@ After working through this guide you should know:
|
||||
Mapping of associations will be covered in the next chapter on
|
||||
:doc:`Association Mapping <association-mapping>`.
|
||||
|
||||
Guide Assumptions
|
||||
-----------------
|
||||
|
||||
You should have already :doc:`installed and configure <configuration>`
|
||||
Doctrine.
|
||||
|
||||
Creating Classes for the Database
|
||||
---------------------------------
|
||||
|
||||
Every PHP object that you want to save in the database using Doctrine
|
||||
is called an "Entity". The term "Entity" describes objects
|
||||
is called an *Entity*. The term "Entity" describes objects
|
||||
that have an identity over many independent requests. This identity is
|
||||
usually achieved by assigning a unique identifier to an entity.
|
||||
In this tutorial the following ``Message`` PHP class will serve as the
|
||||
@@ -50,11 +44,11 @@ that describes your entity.
|
||||
Doctrine provides several different ways to specify object-relational
|
||||
mapping metadata:
|
||||
|
||||
- :doc:`Docblock Annotations <annotations-reference>`
|
||||
- :doc:`Attributes <attributes-reference>`
|
||||
- :doc:`Docblock Annotations <annotations-reference>`
|
||||
- :doc:`XML <xml-mapping>`
|
||||
- :doc:`YAML <yaml-mapping>`
|
||||
- :doc:`PHP code <php-mapping>`
|
||||
- :doc:`YAML <yaml-mapping>` (deprecated and will be removed in ``doctrine/orm`` 3.0.)
|
||||
|
||||
This manual will usually show mapping metadata via docblock annotations, though
|
||||
many examples also show the equivalent configuration in YAML and XML.
|
||||
@@ -62,8 +56,8 @@ many examples also show the equivalent configuration in YAML and XML.
|
||||
.. note::
|
||||
|
||||
All metadata drivers perform equally. Once the metadata of a class has been
|
||||
read from the source (annotations, xml or yaml) it is stored in an instance
|
||||
of the ``Doctrine\ORM\Mapping\ClassMetadata`` class and these instances are
|
||||
read from the source (attributes, annotations, XML, etc.) it is stored in an instance
|
||||
of the ``Doctrine\ORM\Mapping\ClassMetadata`` class which are
|
||||
stored in the metadata cache. If you're not using a metadata cache (not
|
||||
recommended!) then the XML driver is the fastest.
|
||||
|
||||
@@ -71,9 +65,22 @@ Marking our ``Message`` class as an entity for Doctrine is straightforward:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
|
||||
#[Entity]
|
||||
class Message
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
|
||||
/** @Entity */
|
||||
class Message
|
||||
{
|
||||
@@ -100,9 +107,25 @@ You can change this by configuring information about the table:
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
|
||||
#[Entity]
|
||||
#[Table(name: 'message')]
|
||||
class Message
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @Table(name="message")
|
||||
@@ -132,19 +155,38 @@ Now the class ``Message`` will be saved and fetched from the table ``message``.
|
||||
Property Mapping
|
||||
----------------
|
||||
|
||||
The next step after marking a PHP class as an entity is mapping its properties
|
||||
to columns in a table.
|
||||
The next step is mapping its properties to columns in the table.
|
||||
|
||||
To configure a property use the ``@Column`` docblock annotation. The ``type``
|
||||
To configure a property use the ``Column`` docblock annotation. The ``type``
|
||||
attribute specifies the :ref:`Doctrine Mapping Type <reference-mapping-types>`
|
||||
to use for the field. If the type is not specified, ``string`` is used as the
|
||||
default.
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
|
||||
#[Entity]
|
||||
class Message
|
||||
{
|
||||
#[Column(type: Types::INTEGER)]
|
||||
private $id;
|
||||
#[Column(length: 140)]
|
||||
private $text;
|
||||
#[Column(name: 'posted_at', type: Types::DATETIME)]
|
||||
private $postedAt;
|
||||
}
|
||||
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
|
||||
/** @Entity */
|
||||
class Message
|
||||
{
|
||||
@@ -180,36 +222,34 @@ default.
|
||||
column: posted_at
|
||||
|
||||
When we don't explicitly specify a column name via the ``name`` option, Doctrine
|
||||
assumes the field name is also the column name. This means that:
|
||||
assumes the field name is also the column name. So in this example:
|
||||
|
||||
* the ``id`` property will map to the column ``id`` using the type ``integer``;
|
||||
* the ``text`` property will map to the column ``text`` with the default mapping type ``string``;
|
||||
* the ``postedAt`` property will map to the ``posted_at`` column with the ``datetime`` type.
|
||||
|
||||
The Column annotation has some more attributes. Here is a complete
|
||||
list:
|
||||
Here is a complete list of ``Column``s attributes (all optional):
|
||||
|
||||
- ``type``: (optional, defaults to 'string') The mapping type to
|
||||
use for the column.
|
||||
- ``name``: (optional, defaults to field name) The name of the
|
||||
column in the database.
|
||||
- ``length``: (optional, default 255) The length of the column in
|
||||
the database. (Applies only if a string-valued column is used).
|
||||
- ``unique``: (optional, default FALSE) Whether the column is a
|
||||
unique key.
|
||||
- ``nullable``: (optional, default FALSE) Whether the database
|
||||
column is nullable.
|
||||
- ``precision``: (optional, default 0) The precision for a decimal
|
||||
(exact numeric) column (applies only for decimal column),
|
||||
- ``type`` (default: 'string'): The mapping type to use for the column.
|
||||
- ``name`` (default: name of property): The name of the column in the database.
|
||||
- ``length`` (default: 255): The length of the column in the database.
|
||||
Applies only if a string-valued column is used.
|
||||
- ``unique`` (default: ``false``): Whether the column is a unique key.
|
||||
- ``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.
|
||||
- ``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),
|
||||
which is the maximum number of digits that are stored for the values.
|
||||
- ``scale``: (optional, default 0) The scale for a decimal (exact
|
||||
- ``scale`` (default: 0): The scale for a decimal (exact
|
||||
numeric) column (applies only for decimal column), which represents
|
||||
the number of digits to the right of the decimal point and must
|
||||
not be greater than *precision*.
|
||||
- ``columnDefinition``: (optional) Allows to define a custom
|
||||
not be greater than ``precision``.
|
||||
- ``columnDefinition``: Allows to define a custom
|
||||
DDL snippet that is used to create the column. Warning: This normally
|
||||
confuses the SchemaTool to always detect the column as changed.
|
||||
- ``options``: (optional) Key-value pairs of options that get passed
|
||||
confuses the :doc:`SchemaTool <tools>` to always detect the column as changed.
|
||||
- ``options``: Key-value pairs of options that get passed
|
||||
to the underlying database platform when generating DDL statements.
|
||||
|
||||
.. _reference-php-mapping-types:
|
||||
@@ -217,21 +257,35 @@ list:
|
||||
PHP Types Mapping
|
||||
_________________
|
||||
|
||||
Since version 2.9 Doctrine can determine usable defaults from property types
|
||||
on entity classes. When property type is nullable this has no effect on
|
||||
``nullable`` Column attribute at the moment for backwards compatibility
|
||||
reasons.
|
||||
.. versionadded:: 2.9
|
||||
|
||||
Additionally, Doctrine will map PHP types to ``type`` attribute as follows:
|
||||
The column types can be inferred automatically from PHP's property types.
|
||||
However, when the property type is nullable this has no effect on the ``nullable`` Column attribute.
|
||||
|
||||
- ``DateInterval``: ``dateinterval``
|
||||
- ``DateTime``: ``datetime``
|
||||
- ``DateTimeImmutable``: ``datetime_immutable``
|
||||
- ``array``: ``json``
|
||||
- ``bool``: ``boolean``
|
||||
- ``float``: ``float``
|
||||
- ``int``: ``integer``
|
||||
- ``string`` or any other type: ``string``
|
||||
These are the "automatic" mapping rules:
|
||||
|
||||
+-----------------------+-------------------------------+
|
||||
| PHP property type | Doctrine column type |
|
||||
+=======================+===============================+
|
||||
| ``DateInterval`` | ``Types::DATEINTERVAL`` |
|
||||
+-----------------------+-------------------------------+
|
||||
| ``DateTime`` | ``Types::DATETIME_MUTABLE`` |
|
||||
+-----------------------+-------------------------------+
|
||||
| ``DateTimeImmutable`` | ``Types::DATETIME_IMMUTABLE`` |
|
||||
+-----------------------+-------------------------------+
|
||||
| ``array`` | ``Types::JSON`` |
|
||||
+-----------------------+-------------------------------+
|
||||
| ``bool`` | ``Types::BOOLEAN`` |
|
||||
+-----------------------+-------------------------------+
|
||||
| ``float`` | ``Types::FLOAT`` |
|
||||
+-----------------------+-------------------------------+
|
||||
| ``int`` | ``Types::INTEGER`` |
|
||||
+-----------------------+-------------------------------+
|
||||
| Any other type | ``Types::STRING`` |
|
||||
+-----------------------+-------------------------------+
|
||||
|
||||
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``.
|
||||
|
||||
.. _reference-mapping-types:
|
||||
|
||||
@@ -379,11 +433,8 @@ Here is the list of possible generation strategies:
|
||||
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).
|
||||
- ``UUID``: Tells Doctrine to use the built-in Universally Unique Identifier
|
||||
generator. This strategy provides full portability.
|
||||
- ``TABLE``: Tells Doctrine to use a separate table for ID
|
||||
generation. This strategy provides full portability.
|
||||
***This strategy is not yet implemented!***
|
||||
- ``UUID`` (deprecated): Tells Doctrine to use the built-in Universally
|
||||
Unique Identifier generator. This strategy provides full portability.
|
||||
- ``NONE``: Tells Doctrine that the identifiers are assigned (and
|
||||
thus generated) by your code. The assignment must take place before
|
||||
a new entity is passed to ``EntityManager#persist``. NONE is the
|
||||
|
||||
@@ -1,266 +1,14 @@
|
||||
Caching
|
||||
=======
|
||||
|
||||
Doctrine provides cache drivers in the ``doctrine/cache`` package for some
|
||||
of the most popular caching implementations such as APCu, Memcache
|
||||
and Xcache. We also provide an ``ArrayCache`` driver which stores
|
||||
the data in a PHP array. Obviously, when using ``ArrayCache``, the
|
||||
cache does not persist between requests, but this is useful for
|
||||
testing in a development environment.
|
||||
The Doctrine ORM package can leverage cache adapters implementing the PSR-6
|
||||
standard to allow you to improve the performance of various aspects of
|
||||
Doctrine by simply making some additional configurations and method calls.
|
||||
|
||||
Cache Drivers
|
||||
-------------
|
||||
.. _types-of-caches:
|
||||
|
||||
The cache drivers follow a simple interface that is defined in
|
||||
``Doctrine\Common\Cache\Cache``. All the cache drivers extend a
|
||||
base class ``Doctrine\Common\Cache\CacheProvider`` which implements
|
||||
this interface.
|
||||
|
||||
The interface defines the following public methods for you to implement:
|
||||
|
||||
|
||||
- fetch($id) - Fetches an entry from the cache
|
||||
- contains($id) - Test if an entry exists in the cache
|
||||
- save($id, $data, $lifeTime = false) - Puts data into the cache for x seconds. 0 = infinite time
|
||||
- delete($id) - Deletes a cache entry
|
||||
|
||||
Each driver extends the ``CacheProvider`` class which defines a few
|
||||
abstract protected methods that each of the drivers must
|
||||
implement:
|
||||
|
||||
|
||||
- doFetch($id)
|
||||
- doContains($id)
|
||||
- doSave($id, $data, $lifeTime = false)
|
||||
- doDelete($id)
|
||||
|
||||
The public methods ``fetch()``, ``contains()`` etc. use the
|
||||
above protected methods which are implemented by the drivers. The
|
||||
code is organized this way so that the protected methods in the
|
||||
drivers do the raw interaction with the cache implementation and
|
||||
the ``CacheProvider`` can build custom functionality on top of
|
||||
these methods.
|
||||
|
||||
This documentation does not cover every single cache driver included
|
||||
with Doctrine. For an up-to-date-list, see the
|
||||
`cache directory on GitHub <https://github.com/doctrine/cache/tree/2.8.x/lib/Doctrine/Common/Cache>`_.
|
||||
|
||||
PhpFileCache
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The preferred cache driver for metadata and query caches is ``PhpFileCache``.
|
||||
This driver serializes cache items and writes them to a file. This allows for
|
||||
opcode caching to be used and provides high performance in most scenarios.
|
||||
|
||||
In order to use the ``PhpFileCache`` driver it must be able to write to
|
||||
a directory.
|
||||
|
||||
Below is an example of how to use the ``PhpFileCache`` driver by itself.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
The PhpFileCache is not distributed across multiple machines if you are running
|
||||
your application in a distributed setup. This is ok for the metadata and query
|
||||
cache but is not a good approach for the result cache.
|
||||
|
||||
Memcache
|
||||
~~~~~~~~
|
||||
|
||||
In order to use the Memcache cache driver you must have it compiled
|
||||
and enabled in your php.ini. You can read about Memcache
|
||||
`on the PHP website <https://php.net/memcache>`_. It will
|
||||
give you a little background information about what it is and how
|
||||
you can use it as well as how to install it.
|
||||
|
||||
Below is a simple example of how you could use the Memcache cache
|
||||
driver by itself.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$memcache = new Memcache();
|
||||
$memcache->connect('memcache_host', 11211);
|
||||
|
||||
$cacheDriver = new \Doctrine\Common\Cache\MemcacheCache();
|
||||
$cacheDriver->setMemcache($memcache);
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
Memcached
|
||||
~~~~~~~~~
|
||||
|
||||
Memcached is a more recent and complete alternative extension to
|
||||
Memcache.
|
||||
|
||||
In order to use the Memcached cache driver you must have it compiled
|
||||
and enabled in your php.ini. You can read about Memcached
|
||||
`on the PHP website <https://php.net/memcached>`_. It will
|
||||
give you a little background information about what it is and how
|
||||
you can use it as well as how to install it.
|
||||
|
||||
Below is a simple example of how you could use the Memcached cache
|
||||
driver by itself.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$memcached = new Memcached();
|
||||
$memcached->addServer('memcache_host', 11211);
|
||||
|
||||
$cacheDriver = new \Doctrine\Common\Cache\MemcachedCache();
|
||||
$cacheDriver->setMemcached($memcached);
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
Redis
|
||||
~~~~~
|
||||
|
||||
In order to use the Redis cache driver you must have it compiled
|
||||
and enabled in your php.ini. You can read about what Redis is
|
||||
`from here <https://redis.io/>`_. Also check
|
||||
`A PHP extension for Redis <https://github.com/nicolasff/phpredis/>`_ for how you can use
|
||||
and install the Redis PHP extension.
|
||||
|
||||
Below is a simple example of how you could use the Redis cache
|
||||
driver by itself.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$redis = new Redis();
|
||||
$redis->connect('redis_host', 6379);
|
||||
|
||||
$cacheDriver = new \Doctrine\Common\Cache\RedisCache();
|
||||
$cacheDriver->setRedis($redis);
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
Using Cache Drivers
|
||||
-------------------
|
||||
|
||||
In this section we'll describe how you can fully utilize the API of
|
||||
the cache drivers to save data to a cache, check if some cached data
|
||||
exists, fetch the cached data and delete the cached data. We'll use the
|
||||
``ArrayCache`` implementation as our example here.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\ArrayCache();
|
||||
|
||||
Saving
|
||||
~~~~~~
|
||||
|
||||
Saving some data to the cache driver is as simple as using the
|
||||
``save()`` method.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver->save('cache_id', 'my_data');
|
||||
|
||||
The ``save()`` method accepts three arguments which are described
|
||||
below:
|
||||
|
||||
|
||||
- ``$id`` - The cache id
|
||||
- ``$data`` - The cache entry/data.
|
||||
- ``$lifeTime`` - The lifetime. If != false, sets a specific
|
||||
lifetime for this cache entry (null => infinite lifeTime).
|
||||
|
||||
You can save any type of data whether it be a string, array,
|
||||
object, etc.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$array = array(
|
||||
'key1' => 'value1',
|
||||
'key2' => 'value2'
|
||||
);
|
||||
$cacheDriver->save('my_array', $array);
|
||||
|
||||
Checking
|
||||
~~~~~~~~
|
||||
|
||||
Checking whether cached data exists is very simple: just use the
|
||||
``contains()`` method. It accepts a single argument which is the ID
|
||||
of the cache entry.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
if ($cacheDriver->contains('cache_id')) {
|
||||
echo 'cache exists';
|
||||
} else {
|
||||
echo 'cache does not exist';
|
||||
}
|
||||
|
||||
Fetching
|
||||
~~~~~~~~
|
||||
|
||||
Now if you want to retrieve some cache entry you can use the
|
||||
``fetch()`` method. It also accepts a single argument just like
|
||||
``contains()`` which is again the ID of the cache entry.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$array = $cacheDriver->fetch('my_array');
|
||||
|
||||
Deleting
|
||||
~~~~~~~~
|
||||
|
||||
As you might guess, deleting is just as easy as saving, checking
|
||||
and fetching. You can delete by an individual ID, or you can
|
||||
delete all entries.
|
||||
|
||||
By Cache ID
|
||||
^^^^^^^^^^^
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver->delete('my_array');
|
||||
|
||||
All
|
||||
^^^
|
||||
|
||||
If you simply want to delete all cache entries you can do so with
|
||||
the ``deleteAll()`` method.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$deleted = $cacheDriver->deleteAll();
|
||||
|
||||
Namespaces
|
||||
~~~~~~~~~~
|
||||
|
||||
If you heavily use caching in your application and use it in
|
||||
multiple parts of your application, or use it in different
|
||||
applications on the same server you may have issues with cache
|
||||
naming collisions. This can be worked around by using namespaces.
|
||||
You can set the namespace a cache driver should use by using the
|
||||
``setNamespace()`` method.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver->setNamespace('my_namespace_');
|
||||
|
||||
.. _integrating-with-the-orm:
|
||||
|
||||
Integrating with the ORM
|
||||
------------------------
|
||||
|
||||
The Doctrine ORM package is tightly integrated with the cache
|
||||
drivers to allow you to improve the performance of various aspects of
|
||||
Doctrine by simply making some additional configurations and
|
||||
method calls.
|
||||
Types of Caches
|
||||
---------------
|
||||
|
||||
Query Cache
|
||||
~~~~~~~~~~~
|
||||
@@ -276,11 +24,9 @@ use on your ORM configuration.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$cache = new \Symfony\Component\Cache\Adapter\PhpFilesAdapter('doctrine_queries');
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$config->setQueryCacheImpl($cacheDriver);
|
||||
$config->setQueryCache($cache);
|
||||
|
||||
Result Cache
|
||||
~~~~~~~~~~~~
|
||||
@@ -292,11 +38,13 @@ You just need to configure the result cache implementation.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
$cache = new \Symfony\Component\Cache\Adapter\PhpFilesAdapter(
|
||||
'doctrine_results',
|
||||
0,
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$config->setResultCacheImpl($cacheDriver);
|
||||
$config->setResultCache($cache);
|
||||
|
||||
Now when you're executing DQL queries you can configure them to use
|
||||
the result cache.
|
||||
@@ -313,10 +61,12 @@ result cache driver.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
$cache = new \Symfony\Component\Cache\Adapter\PhpFilesAdapter(
|
||||
'doctrine_results',
|
||||
0,
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$query->setResultCacheDriver($cacheDriver);
|
||||
$query->setResultCache($cache);
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -368,11 +118,13 @@ first.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
|
||||
$cache = \Symfony\Component\Cache\Adapter\PhpFilesAdapter(
|
||||
'doctrine_metadata',
|
||||
0,
|
||||
'/path/to/writable/directory'
|
||||
);
|
||||
$config = new \Doctrine\ORM\Configuration();
|
||||
$config->setMetadataCacheImpl($cacheDriver);
|
||||
$config->setMetadataCache($cache);
|
||||
|
||||
Now the metadata information will only be parsed once and stored in
|
||||
the cache driver.
|
||||
@@ -422,30 +174,15 @@ requested many times in a single PHP request. Even though this data
|
||||
may be stored in a fast memory cache, often that cache is over a
|
||||
network link leading to sizable network traffic.
|
||||
|
||||
The ChainCache class allows multiple caches to be registered at once.
|
||||
For example, a per-request ArrayCache can be used first, followed by
|
||||
a (relatively) slower MemcacheCache if the ArrayCache misses.
|
||||
ChainCache automatically handles pushing data up to faster caches in
|
||||
A chain cache class allows multiple caches to be registered at once.
|
||||
For example, a per-request array cache can be used first, followed by
|
||||
a (relatively) slower Memcached cache if the array cache misses.
|
||||
The chain cache automatically handles pushing data up to faster caches in
|
||||
the chain and clearing data in the entire stack when it is deleted.
|
||||
|
||||
A ChainCache takes a simple array of CacheProviders in the order that
|
||||
they should be used.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$arrayCache = new \Doctrine\Common\Cache\ArrayCache();
|
||||
$memcache = new Memcache();
|
||||
$memcache->connect('memcache_host', 11211);
|
||||
$chainCache = new \Doctrine\Common\Cache\ChainCache([
|
||||
$arrayCache,
|
||||
$memcache,
|
||||
]);
|
||||
|
||||
ChainCache itself extends the CacheProvider interface, so it is
|
||||
possible to create chains of chains. While this may seem like an easy
|
||||
way to build a simple high-availability cache, ChainCache does not
|
||||
implement any exception handling so using it as a high-availability
|
||||
mechanism is not recommended.
|
||||
Symfony Cache provides such a chain cache. To find out how to use it,
|
||||
please have a look at the
|
||||
`Symfony Documentation <https://symfony.com/doc/current/components/cache/adapters/chain_adapter.html>`_.
|
||||
|
||||
Cache Slams
|
||||
-----------
|
||||
|
||||
@@ -134,6 +134,32 @@ The check whether the new value is different from the old one is
|
||||
not mandatory but recommended. That way you also have full control
|
||||
over when you consider a property changed.
|
||||
|
||||
If your entity contains an embeddable, you will need to notify
|
||||
separately for each property in the embeddable when it changes
|
||||
for example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// ...
|
||||
|
||||
class MyEntity implements NotifyPropertyChanged
|
||||
{
|
||||
public function setEmbeddable(MyValueObject $embeddable)
|
||||
{
|
||||
if (!$embeddable->equals($this->embeddable)) {
|
||||
// notice the entityField.embeddableField notation for referencing the property
|
||||
$this->_onPropertyChanged('embeddable.prop1', $this->embeddable->getProp1(), $embeddable->getProp1());
|
||||
$this->_onPropertyChanged('embeddable.prop2', $this->embeddable->getProp2(), $embeddable->getProp2());
|
||||
$this->embeddable = $embeddable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
This would update all the fields of the embeddable, you may wish to
|
||||
implement a diff method on your embedded object which returns only
|
||||
the changed fields.
|
||||
|
||||
The negative point of this policy is obvious: You need implement an
|
||||
interface and write some plumbing code. But also note that we tried
|
||||
hard to keep this notification functionality abstract. Strictly
|
||||
|
||||
@@ -41,8 +41,8 @@ access point to ORM functionality provided by Doctrine.
|
||||
// bootstrap.php
|
||||
require_once "vendor/autoload.php";
|
||||
|
||||
use Doctrine\ORM\Tools\Setup;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\ORMSetup;
|
||||
|
||||
$paths = array("/path/to/entity-files");
|
||||
$isDevMode = false;
|
||||
@@ -55,16 +55,21 @@ access point to ORM functionality provided by Doctrine.
|
||||
'dbname' => 'foo',
|
||||
);
|
||||
|
||||
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
|
||||
$config = ORMSetup::createAnnotationMetadataConfiguration($paths, $isDevMode);
|
||||
$entityManager = EntityManager::create($dbParams, $config);
|
||||
|
||||
.. note::
|
||||
|
||||
The ``ORMSetup`` class has been introduced with ORM 2.12. It's predecessor ``Setup`` is deprecated and will
|
||||
be removed in version 3.0.
|
||||
|
||||
Or if you prefer XML:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$paths = array("/path/to/xml-mappings");
|
||||
$config = Setup::createXMLMetadataConfiguration($paths, $isDevMode);
|
||||
$config = ORMSetup::createXMLMetadataConfiguration($paths, $isDevMode);
|
||||
$entityManager = EntityManager::create($dbParams, $config);
|
||||
|
||||
Or if you prefer YAML:
|
||||
@@ -73,7 +78,7 @@ Or if you prefer YAML:
|
||||
|
||||
<?php
|
||||
$paths = array("/path/to/yml-mappings");
|
||||
$config = Setup::createYAMLMetadataConfiguration($paths, $isDevMode);
|
||||
$config = ORMSetup::createYAMLMetadataConfiguration($paths, $isDevMode);
|
||||
$entityManager = EntityManager::create($dbParams, $config);
|
||||
|
||||
.. note::
|
||||
@@ -83,44 +88,29 @@ Or if you prefer YAML:
|
||||
|
||||
"symfony/yaml": "*"
|
||||
|
||||
Inside the ``Setup`` methods several assumptions are made:
|
||||
Inside the ``ORMSetup`` methods several assumptions are made:
|
||||
|
||||
- If `$isDevMode` is true caching is done in memory with the ``ArrayCache``. Proxy objects are recreated on every request.
|
||||
- If `$isDevMode` is false, check for Caches in the order APC, Xcache, Memcache (127.0.0.1:11211), Redis (127.0.0.1:6379) unless `$cache` is passed as fourth argument.
|
||||
- If `$isDevMode` is false, set then proxy classes have to be explicitly created through the command line.
|
||||
- If ``$isDevMode`` is true caching is done in memory with the ``ArrayAdapter``. Proxy objects are recreated on every request.
|
||||
- If ``$isDevMode`` is false, check for Caches in the order APCu, Redis (127.0.0.1:6379), Memcache (127.0.0.1:11211) unless `$cache` is passed as fourth argument.
|
||||
- If ``$isDevMode`` is false, set then proxy classes have to be explicitly created through the command line.
|
||||
- If third argument `$proxyDir` is not set, use the systems temporary directory.
|
||||
|
||||
.. note::
|
||||
|
||||
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.
|
||||
|
||||
.. note::
|
||||
|
||||
You can learn more about the database connection configuration in the
|
||||
`Doctrine DBAL connection configuration reference <https://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html>`_.
|
||||
`Doctrine DBAL connection configuration reference <https://docs.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/configuration.html>`_.
|
||||
|
||||
Setting up the Commandline Tool
|
||||
-------------------------------
|
||||
|
||||
Doctrine ships with a number of command line tools that are very helpful
|
||||
during development. You can call this command from the Composer binary
|
||||
directory:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ php vendor/bin/doctrine
|
||||
|
||||
You need to register your applications EntityManager to the console tool
|
||||
to make use of the tasks by creating a ``cli-config.php`` file with the
|
||||
following content:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
||||
|
||||
// replace with file to your own project bootstrap
|
||||
require_once 'bootstrap.php';
|
||||
|
||||
// replace with mechanism to retrieve EntityManager in your app
|
||||
$entityManager = GetEntityManager();
|
||||
|
||||
return ConsoleRunner::createHelperSet($entityManager);
|
||||
during development. In order to make use of them, create an executable PHP
|
||||
script in your project as described in the
|
||||
:doc:`tools chapter <../reference/tools>`.
|
||||
|
||||
@@ -490,21 +490,21 @@ where you can generate an arbitrary join with the following syntax:
|
||||
With an arbitrary join the result differs from the joins using a mapped property.
|
||||
The result of an arbitrary join is an one dimensional array with a mix of the entity from the ``SELECT``
|
||||
and the joined entity fitting to the filtering of the query. In case of the example with ``User``
|
||||
and ``Blacklist``, it can look like this:
|
||||
and ``Banlist``, it can look like this:
|
||||
|
||||
- User
|
||||
- Blacklist
|
||||
- Blacklist
|
||||
- Banlist
|
||||
- Banlist
|
||||
- User
|
||||
- Blacklist
|
||||
- Banlist
|
||||
- User
|
||||
- Blacklist
|
||||
- Blacklist
|
||||
- Blacklist
|
||||
- Banlist
|
||||
- Banlist
|
||||
- Banlist
|
||||
|
||||
In this form of join, the ``Blacklist`` entities found by the filtering in the ``WITH`` part are not fetched by an accessor
|
||||
method on ``User``, but are already part of the result. In case the accessor method for Blacklists is invoked on a User instance,
|
||||
it loads all the related ``Blacklist`` objects corresponding to this ``User``. This change of behaviour needs to be considered
|
||||
In this form of join, the ``Banlist`` entities found by the filtering in the ``WITH`` part are not fetched by an accessor
|
||||
method on ``User``, but are already part of the result. In case the accessor method for Banlists is invoked on a User instance,
|
||||
it loads all the related ``Banlist`` objects corresponding to this ``User``. This change of behaviour needs to be considered
|
||||
when the DQL is switched to an arbitrary join.
|
||||
|
||||
.. note::
|
||||
@@ -670,11 +670,23 @@ The same restrictions apply for the reference of related entities.
|
||||
|
||||
.. warning::
|
||||
|
||||
DQL DELETE statements are ported directly into a
|
||||
Database DELETE statement and therefore bypass any events and checks for the
|
||||
version column if they are not explicitly added to the WHERE clause
|
||||
of the query. Additionally Deletes of specified entities are *NOT*
|
||||
cascaded to related entities even if specified in the metadata.
|
||||
DQL DELETE statements are ported directly into an SQL DELETE statement.
|
||||
Therefore, some limitations apply:
|
||||
|
||||
- Lifecycle events for the affected entities are not executed.
|
||||
- A cascading ``remove`` operation (as indicated e. g. by ``cascade={"remove"}``
|
||||
or ``cascade={"all"}`` in the mapping configuration) is not being performed
|
||||
for associated entities. You can rely on database level cascade operations by
|
||||
configuring each join column with the ``onDelete`` option.
|
||||
- Checks for the version column are bypassed if they are not explicitly added
|
||||
to the WHERE clause of the query.
|
||||
|
||||
When you rely on one of these features, one option is to use the
|
||||
``EntityManager#remove($entity)`` method. This, however, is costly performance-wise:
|
||||
It means collections and related entities are fetched into memory
|
||||
(even if they are marked as lazy). Pulling object graphs into memory on cascade
|
||||
can cause considerable performance overhead, especially when the cascaded collections
|
||||
are large. Make sure to weigh the benefits and downsides.
|
||||
|
||||
Comments in queries
|
||||
-------------------
|
||||
@@ -718,7 +730,7 @@ clauses:
|
||||
- ``SQRT(q)`` - Return the square-root of q.
|
||||
- ``SUBSTRING(str, start [, length])`` - Return substring of given
|
||||
string.
|
||||
- ``TRIM([LEADING \| TRAILING \| BOTH] ['trchar' FROM] str)`` - Trim
|
||||
- ``TRIM([LEADING | TRAILING | BOTH] ['trchar' FROM] str)`` - Trim
|
||||
the string by the given trim char, defaults to whitespaces.
|
||||
- ``UPPER(str)`` - Return the upper-case of the given string.
|
||||
- ``DATE_ADD(date, value, unit)`` - Add the given time to a given date.
|
||||
@@ -1184,6 +1196,7 @@ The constants for the different hydration modes are:
|
||||
- ``Query::HYDRATE_ARRAY``
|
||||
- ``Query::HYDRATE_SCALAR``
|
||||
- ``Query::HYDRATE_SINGLE_SCALAR``
|
||||
- ``Query::HYDRATE_SCALAR_COLUMN``
|
||||
|
||||
Object Hydration
|
||||
^^^^^^^^^^^^^^^^
|
||||
@@ -1272,6 +1285,25 @@ You can use the ``getSingleScalarResult()`` shortcut as well:
|
||||
<?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
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1283,13 +1315,14 @@ creating a class which extends ``AbstractHydrator``:
|
||||
<?php
|
||||
namespace MyProject\Hydrators;
|
||||
|
||||
use Doctrine\DBAL\FetchMode;
|
||||
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
|
||||
|
||||
class CustomHydrator extends AbstractHydrator
|
||||
{
|
||||
protected function _hydrateAll()
|
||||
{
|
||||
return $this->_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
return $this->_stmt->fetchAll(FetchMode::FETCH_ASSOC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1498,6 +1531,8 @@ Given that there are 10 users and corresponding addresses in the database the ex
|
||||
a one-by-one basis once they are accessed.
|
||||
|
||||
|
||||
.. _dql_ebnf_grammar:
|
||||
|
||||
EBNF
|
||||
----
|
||||
|
||||
@@ -1526,7 +1561,6 @@ Terminals
|
||||
|
||||
- identifier (name, email, ...) must match ``[a-z_][a-z0-9_]*``
|
||||
- fully_qualified_name (Doctrine\Tests\Models\CMS\CmsUser) matches PHP's fully qualified class names
|
||||
- aliased_name (CMS:CmsUser) uses two identifiers, one for the namespace alias and one for the class inside it
|
||||
- string ('foo', 'bar''s house', '%ninja%', ...)
|
||||
- char ('/', '\\', ' ', ...)
|
||||
- integer (-1, 0, 1, 34, ...)
|
||||
@@ -1692,7 +1726,7 @@ Literal Values
|
||||
.. code-block:: php
|
||||
|
||||
Literal ::= string | char | integer | float | boolean
|
||||
InParameter ::= Literal | InputParameter
|
||||
InParameter ::= ArithmeticExpression | InputParameter
|
||||
|
||||
Input Parameter
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -79,7 +79,9 @@ array of events it should be subscribed to.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class TestEventSubscriber implements \Doctrine\Common\EventSubscriber
|
||||
use Doctrine\Common\EventSubscriber;
|
||||
|
||||
class TestEventSubscriber implements EventSubscriber
|
||||
{
|
||||
public $preFooInvoked = false;
|
||||
|
||||
@@ -121,6 +123,56 @@ Now you can test the ``$eventSubscriber`` instance to see if the
|
||||
echo 'pre foo invoked!';
|
||||
}
|
||||
|
||||
Registering Event Handlers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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>`
|
||||
* For *some events* (see table below), you can create a *Lifecycle Callback* method in the
|
||||
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`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
|
||||
Naming convention
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -140,103 +192,7 @@ several reasons:
|
||||
An example for a correct notation can be found in the example
|
||||
``TestEvent`` above.
|
||||
|
||||
.. _reference-events-lifecycle-events:
|
||||
|
||||
Lifecycle Events
|
||||
----------------
|
||||
|
||||
The ``EntityManager`` and ``UnitOfWork`` classes trigger a bunch of
|
||||
events during the life-time of their registered entities.
|
||||
|
||||
|
||||
|
||||
- ``preRemove`` - The ``preRemove`` event occurs for a given entity
|
||||
before the respective ``EntityManager`` remove operation for that
|
||||
entity is executed. It is not called for a DQL ``DELETE`` statement.
|
||||
- ``postRemove`` - 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.
|
||||
- ``prePersist`` - The ``prePersist`` event occurs for a given entity
|
||||
before the respective ``EntityManager`` persist operation for that
|
||||
entity is executed. It should be noted that this event is only triggered on
|
||||
*initial* persist of an entity (i.e. it does not trigger on future updates).
|
||||
- ``postPersist`` - 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.
|
||||
- ``preUpdate`` - The ``preUpdate`` event occurs before the database
|
||||
update operations to entity data. It is not called for a DQL
|
||||
``UPDATE`` statement nor when the computed changeset is empty.
|
||||
- ``postUpdate`` - The ``postUpdate`` event occurs after the database
|
||||
update operations to entity data. It is not called for a DQL
|
||||
``UPDATE`` statement.
|
||||
- ``postLoad`` - The postLoad event occurs for an entity after the
|
||||
entity has been loaded into the current ``EntityManager`` from the
|
||||
database or after the refresh operation has been applied to it.
|
||||
- ``loadClassMetadata`` - The ``loadClassMetadata`` event occurs after the
|
||||
mapping metadata for a class has been loaded from a mapping source
|
||||
(annotations/xml/yaml). This event is not a lifecycle callback.
|
||||
- ``onClassMetadataNotFound`` - Loading class metadata for a particular
|
||||
requested class name failed. Manipulating the given event args instance
|
||||
allows providing fallback metadata even when no actual metadata exists
|
||||
or could be found. This event is not a lifecycle callback.
|
||||
- ``preFlush`` - The ``preFlush`` event occurs at the very beginning of
|
||||
a flush operation.
|
||||
- ``onFlush`` - The ``onFlush`` event occurs after the change-sets of all
|
||||
managed entities are computed. This event is not a lifecycle
|
||||
callback.
|
||||
- ``postFlush`` - The ``postFlush`` event occurs at the end of a flush operation. This
|
||||
event is not a lifecycle callback.
|
||||
- ``onClear`` - The ``onClear`` event occurs when the
|
||||
``EntityManager#clear()`` operation is invoked, after all references
|
||||
to entities have been removed from the unit of work. This event is not
|
||||
a lifecycle callback.
|
||||
|
||||
|
||||
.. warning::
|
||||
|
||||
Note that, when using ``Doctrine\ORM\AbstractQuery#toIterable()``, ``postLoad``
|
||||
events will be executed immediately after objects are being hydrated, and therefore
|
||||
associations are not guaranteed to be initialized. It is not safe to combine
|
||||
usage of ``Doctrine\ORM\AbstractQuery#toIterable()`` and ``postLoad`` event
|
||||
handlers.
|
||||
|
||||
.. warning::
|
||||
|
||||
Note that the ``postRemove`` event or any events triggered after an entity removal
|
||||
can receive an uninitializable proxy in case you have configured an entity to
|
||||
cascade remove relations. In this case, you should load yourself the proxy in
|
||||
the associated pre event.
|
||||
|
||||
You can access the Event constants from the ``Events`` class in the
|
||||
ORM package.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Events;
|
||||
echo Events::preUpdate;
|
||||
|
||||
These can be hooked into by two different types of event
|
||||
listeners:
|
||||
|
||||
- Lifecycle Callbacks are methods on the entity classes that are
|
||||
called when the event is triggered. They receive some kind
|
||||
of ``EventArgs`` instance.
|
||||
- Lifecycle Event Listeners and Subscribers are classes with specific callback
|
||||
methods that receives some kind of ``EventArgs`` instance.
|
||||
|
||||
The ``EventArgs`` instance received by the listener gives access to the entity,
|
||||
``EntityManager`` instance and other relevant data.
|
||||
|
||||
.. note::
|
||||
|
||||
All Lifecycle events that happen during the ``flush()`` of
|
||||
an ``EntityManager`` have very specific constraints on the allowed
|
||||
operations that can be executed. Please read the
|
||||
:ref:`reference-events-implementing-listeners` section very carefully
|
||||
to understand which operations are allowed in which lifecycle event.
|
||||
|
||||
.. _lifecycle-callbacks:
|
||||
|
||||
Lifecycle Callbacks
|
||||
-------------------
|
||||
@@ -250,138 +206,108 @@ specific to a particular entity class's lifecycle.
|
||||
|
||||
.. note::
|
||||
|
||||
Note that Licecycle Callbacks are not supported for Embeddables.
|
||||
Lifecycle Callbacks are not supported for :doc:`Embeddables </tutorials/embeddables>`.
|
||||
|
||||
.. code-block:: php
|
||||
.. configuration-block::
|
||||
|
||||
<?php
|
||||
.. code-block:: attribute
|
||||
|
||||
/** @Entity @HasLifecycleCallbacks */
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
<?php
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
|
||||
#[Entity]
|
||||
#[HasLifecycleCallbacks]
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
|
||||
#[Column(type: Types::STRING, length: 255)]
|
||||
public $value;
|
||||
|
||||
#[PrePersist]
|
||||
public function doStuffOnPrePersist(LifecycleEventArgs $eventArgs)
|
||||
{
|
||||
$this->createdAt = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
#[PrePersist]
|
||||
public function doOtherStuffOnPrePersist()
|
||||
{
|
||||
$this->value = 'changed from prePersist callback!';
|
||||
}
|
||||
|
||||
#[PreUpdate]
|
||||
public function doStuffOnPreUpdate(PreUpdateEventArgs $eventArgs)
|
||||
{
|
||||
$this->value = 'changed from preUpdate callback!';
|
||||
}
|
||||
}
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
|
||||
/**
|
||||
* @Column(type="string", length=255)
|
||||
* @Entity
|
||||
* @HasLifecycleCallbacks
|
||||
*/
|
||||
public $value;
|
||||
|
||||
/** @Column(name="created_at", type="string", length=255) */
|
||||
private $createdAt;
|
||||
|
||||
/** @PrePersist */
|
||||
public function doStuffOnPrePersist()
|
||||
{
|
||||
$this->createdAt = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
/** @PrePersist */
|
||||
public function doOtherStuffOnPrePersist()
|
||||
{
|
||||
$this->value = 'changed from prePersist callback!';
|
||||
}
|
||||
|
||||
/** @PostPersist */
|
||||
public function doStuffOnPostPersist()
|
||||
{
|
||||
$this->value = 'changed from postPersist callback!';
|
||||
}
|
||||
|
||||
/** @PostLoad */
|
||||
public function doStuffOnPostLoad()
|
||||
{
|
||||
$this->value = 'changed from postLoad callback!';
|
||||
}
|
||||
|
||||
/** @PreUpdate */
|
||||
public function doStuffOnPreUpdate()
|
||||
{
|
||||
$this->value = 'changed from preUpdate callback!';
|
||||
}
|
||||
}
|
||||
|
||||
Note that the methods set as lifecycle callbacks need to be public and,
|
||||
when using these annotations, you have to apply the
|
||||
``@HasLifecycleCallbacks`` marker annotation on the entity class.
|
||||
|
||||
If you want to register lifecycle callbacks from YAML or XML you
|
||||
can do it with the following.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
fields:
|
||||
# ...
|
||||
name:
|
||||
type: string(50)
|
||||
lifecycleCallbacks:
|
||||
prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersist ]
|
||||
postPersist: [ doStuffOnPostPersist ]
|
||||
|
||||
In YAML the ``key`` of the lifecycleCallbacks entry is the event that you
|
||||
are triggering on and the value is the method (or methods) to call. The allowed
|
||||
event types are the ones listed in the previous Lifecycle Events section.
|
||||
|
||||
XML would look something like this:
|
||||
|
||||
.. 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="User">
|
||||
|
||||
<lifecycle-callbacks>
|
||||
<lifecycle-callback type="prePersist" method="doStuffOnPrePersist"/>
|
||||
<lifecycle-callback type="postPersist" method="doStuffOnPostPersist"/>
|
||||
</lifecycle-callbacks>
|
||||
|
||||
</entity>
|
||||
|
||||
</doctrine-mapping>
|
||||
|
||||
In XML the ``type`` of the lifecycle-callback entry is the event that you
|
||||
are triggering on and the ``method`` is the method to call. The allowed event
|
||||
types are the ones listed in the previous Lifecycle Events section.
|
||||
|
||||
When using YAML or XML you need to remember to create public methods to match the
|
||||
callback names you defined. E.g. in these examples ``doStuffOnPrePersist()``,
|
||||
``doOtherStuffOnPrePersist()`` and ``doStuffOnPostPersist()`` methods need to be
|
||||
defined on your ``User`` model.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// ...
|
||||
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
|
||||
public function doStuffOnPrePersist()
|
||||
class User
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
public function doOtherStuffOnPrePersist()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
/** @Column(type="string", length=255) */
|
||||
public $value;
|
||||
|
||||
public function doStuffOnPostPersist()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
/** @PrePersist */
|
||||
public function doStuffOnPrePersist(LifecycleEventArgs $eventArgs)
|
||||
{
|
||||
$this->createdAt = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
/** @PrePersist */
|
||||
public function doOtherStuffOnPrePersist()
|
||||
{
|
||||
$this->value = 'changed from prePersist callback!';
|
||||
}
|
||||
|
||||
/** @PreUpdate */
|
||||
public function doStuffOnPreUpdate(PreUpdateEventArgs $eventArgs)
|
||||
{
|
||||
$this->value = 'changed from preUpdate callback!';
|
||||
}
|
||||
}
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<doctrine-mapping xmlns="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="User">
|
||||
<!-- ... -->
|
||||
<lifecycle-callbacks>
|
||||
<lifecycle-callback type="prePersist" method="doStuffOnPrePersist"/>
|
||||
<lifecycle-callback type="prePersist" method="doOtherStuffOnPrePersist"/>
|
||||
<lifecycle-callback type="preUpdate" method="doStuffOnPreUpdate"/>
|
||||
</lifecycle-callbacks>
|
||||
</entity>
|
||||
</doctrine-mapping>
|
||||
.. code-block:: yaml
|
||||
|
||||
User:
|
||||
type: entity
|
||||
fields:
|
||||
# ...
|
||||
value:
|
||||
type: string(255)
|
||||
lifecycleCallbacks:
|
||||
prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersist ]
|
||||
preUpdate: [ doStuffOnPreUpdate ]
|
||||
|
||||
Lifecycle Callbacks Event Argument
|
||||
-----------------------------------
|
||||
----------------------------------
|
||||
|
||||
The triggered event is also given to the lifecycle-callback.
|
||||
|
||||
@@ -403,6 +329,8 @@ With the additional argument you have access to the
|
||||
}
|
||||
}
|
||||
|
||||
.. _listening-and-subscribing-to-lifecycle-events:
|
||||
|
||||
Listening and subscribing to Lifecycle Events
|
||||
---------------------------------------------
|
||||
|
||||
@@ -413,7 +341,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:`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
|
||||
@@ -482,8 +410,10 @@ EventManager that is passed to the EntityManager factory:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Events;
|
||||
|
||||
$eventManager = new EventManager();
|
||||
$eventManager->addEventListener(array(Events::preUpdate), new MyEventListener());
|
||||
$eventManager->addEventListener([Events::preUpdate], new MyEventListener());
|
||||
$eventManager->addEventSubscriber(new MyEventSubscriber());
|
||||
|
||||
$entityManager = EntityManager::create($dbOpts, $config, $eventManager);
|
||||
@@ -494,7 +424,9 @@ EntityManager was created:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$entityManager->getEventManager()->addEventListener(array(Events::preUpdate), new MyEventListener());
|
||||
use Doctrine\ORM\Events;
|
||||
|
||||
$entityManager->getEventManager()->addEventListener([Events::preUpdate], new MyEventListener());
|
||||
$entityManager->getEventManager()->addEventSubscriber(new MyEventSubscriber());
|
||||
|
||||
.. _reference-events-implementing-listeners:
|
||||
@@ -514,24 +446,28 @@ the restrictions apply as well, with the additional restriction
|
||||
that (prior to version 2.4) you do not have access to the
|
||||
``EntityManager`` or ``UnitOfWork`` APIs inside these events.
|
||||
|
||||
.. _reference-events-pre-persist:
|
||||
|
||||
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 cascaded associations.
|
||||
There are two ways for the ``prePersist`` event to be triggered:
|
||||
|
||||
There is another way for ``prePersist`` to be called, inside the
|
||||
- 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 cascade persist. Any new entity found
|
||||
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 "persistence by reachability".
|
||||
on it. This is called :ref:`persistence by reachability<persistence-by-reachability>`.
|
||||
|
||||
In both cases you get passed a ``LifecycleEventArgs`` instance
|
||||
which has access to the entity and the entity manager.
|
||||
|
||||
The following restrictions apply to ``prePersist``:
|
||||
This event is only triggered on *initial* persist of an entity
|
||||
(i.e. it does not trigger on future updates).
|
||||
|
||||
The following restrictions apply to ``prePersist``:
|
||||
|
||||
- If you are using a PrePersist Identity Generator such as
|
||||
sequences the ID value will *NOT* be available within any
|
||||
@@ -540,29 +476,34 @@ The following restrictions apply to ``prePersist``:
|
||||
event. This includes modifications to
|
||||
collections such as additions, removals or replacement.
|
||||
|
||||
.. _reference-events-pre-remove:
|
||||
|
||||
preRemove
|
||||
~~~~~~~~~
|
||||
|
||||
The ``preRemove`` event is called on every entity when its passed
|
||||
to the ``EntityManager#remove()`` method. It is cascaded for all
|
||||
associations that are marked as cascade delete.
|
||||
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>`
|
||||
|
||||
It is not called for a DQL ``DELETE`` statement.
|
||||
|
||||
There are no restrictions to what methods can be called inside the
|
||||
``preRemove`` event, except when the remove method itself was
|
||||
called during a flush operation.
|
||||
|
||||
.. _reference-events-pre-flush:
|
||||
|
||||
preFlush
|
||||
~~~~~~~~
|
||||
|
||||
``preFlush`` is called at ``EntityManager#flush()`` before
|
||||
anything else. ``EntityManager#flush()`` should not be called inside
|
||||
its listeners, since `preFlush` event is dispatched in it, which would
|
||||
result in infinite loop.
|
||||
``preFlush`` is called inside ``EntityManager::flush()`` before
|
||||
anything else. ``EntityManager::flush()`` must not be called inside
|
||||
its listeners, since it would fire the ``preFlush`` event again, which would
|
||||
result in an infinite loop.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\ORM\Event\PreFlushEventArgs;
|
||||
|
||||
class PreFlushExampleListener
|
||||
@@ -573,15 +514,16 @@ result in infinite loop.
|
||||
}
|
||||
}
|
||||
|
||||
.. _reference-events-on-flush:
|
||||
|
||||
onFlush
|
||||
~~~~~~~
|
||||
|
||||
OnFlush is a very powerful event. It is called inside
|
||||
``EntityManager#flush()`` after the changes to all the managed
|
||||
``onFlush`` is a very powerful event. It is called inside
|
||||
``EntityManager::flush()`` after the changes to all the managed
|
||||
entities and their associations have been computed. This means, the
|
||||
``onFlush`` event has access to the sets of:
|
||||
|
||||
|
||||
- Entities scheduled for insert
|
||||
- Entities scheduled for update
|
||||
- Entities scheduled for removal
|
||||
@@ -589,7 +531,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 ``UnitOfWork`` 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
|
||||
@@ -624,11 +566,10 @@ mentioned sets. See this example:
|
||||
}
|
||||
}
|
||||
|
||||
The following restrictions apply to the onFlush event:
|
||||
|
||||
The following restrictions apply to the ``onFlush`` event:
|
||||
|
||||
- If you create and persist a new entity in ``onFlush``, then
|
||||
calling ``EntityManager#persist()`` is not enough.
|
||||
calling ``EntityManager::persist()`` is not enough.
|
||||
You have to execute an additional call to
|
||||
``$unitOfWork->computeChangeSet($classMetadata, $entity)``.
|
||||
- Changing primitive fields or associations requires you to
|
||||
@@ -636,16 +577,18 @@ The following restrictions apply to the onFlush event:
|
||||
affected entity. This can be done by calling
|
||||
``$unitOfWork->recomputeSingleEntityChangeSet($classMetadata, $entity)``.
|
||||
|
||||
.. _reference-events-post-flush:
|
||||
|
||||
postFlush
|
||||
~~~~~~~~~
|
||||
|
||||
``postFlush`` is called at the end of ``EntityManager#flush()``.
|
||||
``EntityManager#flush()`` can **NOT** be called safely inside its listeners.
|
||||
``postFlush`` is called at the end of ``EntityManager::flush()``.
|
||||
``EntityManager::flush()`` can **NOT** be called safely inside its listeners.
|
||||
This event is not a lifecycle callback.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\ORM\Event\PostFlushEventArgs;
|
||||
|
||||
class PostFlushExampleListener
|
||||
@@ -656,26 +599,27 @@ postFlush
|
||||
}
|
||||
}
|
||||
|
||||
.. _reference-events-pre-update:
|
||||
|
||||
preUpdate
|
||||
~~~~~~~~~
|
||||
|
||||
PreUpdate is the most restrictive to use event, since it is called
|
||||
right before an update statement is called for an entity inside the
|
||||
``EntityManager#flush()`` method. Note that this event is not
|
||||
triggered when the computed changeset is empty.
|
||||
PreUpdate is called inside the ``EntityManager::flush()`` method,
|
||||
right before an SQL ``UPDATE`` statement. This event is not
|
||||
triggered when the computed changeset is empty, nor for a DQL
|
||||
``UPDATE`` statement.
|
||||
|
||||
Changes to associations of the updated entity are never allowed in
|
||||
this event, since Doctrine cannot guarantee to correctly handle
|
||||
referential integrity at this point of the flush operation. This
|
||||
event has a powerful feature however, it is executed with a
|
||||
``PreUpdateEventArgs`` instance, which contains a reference to the
|
||||
`PreUpdateEventArgs`_ instance, which contains a reference to the
|
||||
computed change-set of this entity.
|
||||
|
||||
This means you have access to all the fields that have changed for
|
||||
this entity with their old and new value. The following methods are
|
||||
available on the ``PreUpdateEventArgs``:
|
||||
|
||||
|
||||
- ``getEntity()`` to get access to the actual entity.
|
||||
- ``getEntityChangeSet()`` to get a copy of the changeset array.
|
||||
Changes to this returned array do not affect updating.
|
||||
@@ -691,6 +635,8 @@ A simple example for this event looks like:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
class NeverAliceOnlyBobListener
|
||||
{
|
||||
public function preUpdate(PreUpdateEventArgs $eventArgs)
|
||||
@@ -710,6 +656,8 @@ lifecycle callback when there are expensive validations to call:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
class ValidCreditCardListener
|
||||
{
|
||||
public function preUpdate(PreUpdateEventArgs $eventArgs)
|
||||
@@ -729,32 +677,70 @@ lifecycle callback when there are expensive validations to call:
|
||||
|
||||
Restrictions for this event:
|
||||
|
||||
|
||||
- Changes to associations of the passed entities are not
|
||||
recognized by the flush operation anymore.
|
||||
- Changes to fields of the passed entities are not recognized by
|
||||
the flush operation anymore, use the computed change-set passed to
|
||||
the event to modify primitive field values, e.g. use
|
||||
``$eventArgs->setNewValue($field, $value);`` as in the Alice to Bob example above.
|
||||
- Any calls to ``EntityManager#persist()`` or
|
||||
``EntityManager#remove()``, even in combination with the ``UnitOfWork``
|
||||
- Any calls to ``EntityManager::persist()`` or
|
||||
``EntityManager::remove()``, even in combination with the ``UnitOfWork``
|
||||
API are strongly discouraged and don't work as expected outside the
|
||||
flush operation.
|
||||
|
||||
.. _reference-events-post-update-remove-persist:
|
||||
|
||||
postUpdate, postRemove, postPersist
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The 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.
|
||||
- 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.
|
||||
|
||||
.. warning::
|
||||
|
||||
The ``postRemove`` event or any events triggered after an entity removal
|
||||
can receive an uninitializable proxy in case you have configured an entity to
|
||||
cascade remove relations. In this case, you should load yourself the proxy in
|
||||
the associated ``pre*`` event.
|
||||
|
||||
.. _reference-events-post-load:
|
||||
|
||||
postLoad
|
||||
~~~~~~~~
|
||||
|
||||
This event is called after an entity is constructed by the
|
||||
EntityManager.
|
||||
The postLoad event occurs after the entity has been loaded into the current
|
||||
``EntityManager`` from the database or after ``refresh()`` has been applied to it.
|
||||
|
||||
.. warning::
|
||||
|
||||
When using ``Doctrine\ORM\AbstractQuery::toIterable()``, ``postLoad``
|
||||
events will be executed immediately after objects are being hydrated, and therefore
|
||||
associations are not guaranteed to be initialized. It is not safe to combine
|
||||
usage of ``Doctrine\ORM\AbstractQuery::toIterable()`` and ``postLoad`` event
|
||||
handlers.
|
||||
|
||||
.. _reference-events-on-clear:
|
||||
|
||||
onClear
|
||||
~~~~~~~~
|
||||
|
||||
The ``onClear`` event occurs when the ``EntityManager::clear()`` operation is invoked,
|
||||
after all references to entities have been removed from the unit of work.
|
||||
This event is not a lifecycle callback.
|
||||
|
||||
Entity listeners
|
||||
----------------
|
||||
@@ -766,7 +752,19 @@ An entity listener is a lifecycle listener class used for an entity.
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: php
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
namespace MyProject\Entity;
|
||||
use App\EventListener\UserListener;
|
||||
|
||||
#[Entity]
|
||||
#[EntityListeners([UserListener::class])]
|
||||
class User
|
||||
{
|
||||
// ....
|
||||
}
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
namespace MyProject\Entity;
|
||||
@@ -811,6 +809,8 @@ An ``Entity Listener`` could be any class, by default it should be a class with
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
class UserListener
|
||||
{
|
||||
public function preUpdate(User $user, PreUpdateEventArgs $event)
|
||||
@@ -827,6 +827,10 @@ you need to map the listener method using the event type mapping:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
use Doctrine\ORM\Event\PreFlushEventArgs;
|
||||
|
||||
class UserListener
|
||||
{
|
||||
/** @PrePersist */
|
||||
@@ -900,7 +904,7 @@ you need to map the listener method using the event type mapping:
|
||||
|
||||
|
||||
Entity listeners resolver
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Doctrine invokes the listener resolver to get the listener instance.
|
||||
|
||||
- A resolver allows you register a specific entity listener instance.
|
||||
@@ -911,6 +915,8 @@ Specifying an entity listener instance :
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
// User.php
|
||||
|
||||
/** @Entity @EntityListeners({"UserListener"}) */
|
||||
@@ -937,12 +943,14 @@ Specifying an entity listener instance :
|
||||
$listener = $container->get('user_listener');
|
||||
$em->getConfiguration()->getEntityListenerResolver()->register($listener);
|
||||
|
||||
Implementing your own resolver :
|
||||
Implementing your own resolver:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class MyEntityListenerResolver extends \Doctrine\ORM\Mapping\DefaultEntityListenerResolver
|
||||
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
|
||||
|
||||
class MyEntityListenerResolver extends DefaultEntityListenerResolver
|
||||
{
|
||||
public function __construct($container)
|
||||
{
|
||||
@@ -962,24 +970,29 @@ Implementing your own resolver :
|
||||
$configurations->setEntityListenerResolver(new MyEntityListenerResolver);
|
||||
EntityManager::create(.., $configurations, ..);
|
||||
|
||||
.. _reference-events-load-class-metadata:
|
||||
|
||||
Load ClassMetadata Event
|
||||
------------------------
|
||||
|
||||
When the mapping information for an entity is read, it is populated
|
||||
in to a ``ClassMetadataInfo`` instance. You can hook in to this
|
||||
process and manipulate the instance.
|
||||
``loadClassMetadata`` - The ``loadClassMetadata`` event occurs after the
|
||||
mapping metadata for a class has been loaded from a mapping source
|
||||
(annotations/xml/yaml) in to a ``Doctrine\ORM\Mapping\ClassMetadata`` instance.
|
||||
You can hook in to this process and manipulate the instance.
|
||||
This event is not a lifecycle callback.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$test = new TestEvent();
|
||||
$metadataFactory = $em->getMetadataFactory();
|
||||
$evm = $em->getEventManager();
|
||||
$evm->addEventListener(Events::loadClassMetadata, $test);
|
||||
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
|
||||
|
||||
class TestEvent
|
||||
$test = new TestEventListener();
|
||||
$evm = $em->getEventManager();
|
||||
$evm->addEventListener(Doctrine\ORM\Events::loadClassMetadata, $test);
|
||||
|
||||
class TestEventListener
|
||||
{
|
||||
public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs)
|
||||
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
|
||||
{
|
||||
$classMetadata = $eventArgs->getClassMetadata();
|
||||
$fieldMapping = array(
|
||||
@@ -991,3 +1004,75 @@ process and manipulate the instance.
|
||||
}
|
||||
}
|
||||
|
||||
If not class metadata can be found, an ``onClassMetadataNotFound`` event is dispatched.
|
||||
Manipulating the given event args instance
|
||||
allows providing fallback metadata even when no actual metadata exists
|
||||
or could be found. This event is not a lifecycle callback.
|
||||
|
||||
SchemaTool Events
|
||||
-----------------
|
||||
|
||||
It is possible to access the schema metadata during schema changes that are happening in ``Doctrine\ORM\Tools\SchemaTool``.
|
||||
There are two different events where you can hook in.
|
||||
|
||||
postGenerateSchemaTable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This event is fired for each ``Doctrine\DBAL\Schema\Table`` instance, after one was created and built up with the current class metadata
|
||||
of an entity. It is possible to access to the current state of ``Doctrine\DBAL\Schema\Schema``, the current table schema
|
||||
instance and class metadata.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Tools\ToolEvents;
|
||||
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;
|
||||
|
||||
$test = new TestEventListener();
|
||||
$evm = $em->getEventManager();
|
||||
$evm->addEventListener(ToolEvents::postGenerateSchemaTable, $test);
|
||||
|
||||
class TestEventListener
|
||||
{
|
||||
public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $eventArgs)
|
||||
{
|
||||
$classMetadata = $eventArgs->getClassMetadata();
|
||||
$schema = $eventArgs->getSchema();
|
||||
$table = $eventArgs->getClassTable();
|
||||
}
|
||||
}
|
||||
|
||||
postGenerateSchema
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This event is fired after the schema instance was successfully built and before SQL queries are generated from the
|
||||
schema information of ``Doctrine\DBAL\Schema\Schema``. It allows to access the full object representation of the database schema
|
||||
and the EntityManager.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Tools\ToolEvents;
|
||||
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
|
||||
|
||||
$test = new TestEventListener();
|
||||
$evm = $em->getEventManager();
|
||||
$evm->addEventListener(ToolEvents::postGenerateSchema, $test);
|
||||
|
||||
class TestEventListener
|
||||
{
|
||||
public function postGenerateSchema(GenerateSchemaEventArgs $eventArgs)
|
||||
{
|
||||
$schema = $eventArgs->getSchema();
|
||||
$em = $eventArgs->getEntityManager();
|
||||
}
|
||||
}
|
||||
|
||||
.. _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
|
||||
|
||||
@@ -11,7 +11,7 @@ request and can greatly improve performance.
|
||||
"If you care about performance and don't use a bytecode
|
||||
cache then you don't really care about performance. Please get one
|
||||
and start using it."
|
||||
|
||||
|
||||
*Stas Malyshev, Core Contributor to PHP and Zend Employee*
|
||||
|
||||
|
||||
@@ -27,11 +27,13 @@ Doctrine will need to load your mapping information on every single
|
||||
request and has to parse each DQL query on every single request.
|
||||
This is a waste of resources.
|
||||
|
||||
The preferred cache driver for metadata and query caches is ``PhpFileCache``.
|
||||
This driver serializes cache items and writes them to a file.
|
||||
The preferred cache adapter for metadata and query caches is a PHP file
|
||||
cache like Symfony's
|
||||
`PHP files adapter <https://symfony.com/doc/current/components/cache/adapters/php_files_adapter.html>`_.
|
||||
This kind of cache serializes cache items and writes them to a file.
|
||||
This allows for opcode caching to be used and provides high performance in most scenarios.
|
||||
|
||||
See :ref:`integrating-with-the-orm`
|
||||
See :ref:`types-of-caches`
|
||||
|
||||
Alternative Query Result Formats
|
||||
--------------------------------
|
||||
|
||||
@@ -39,8 +39,9 @@ an entity.
|
||||
$em->getConfiguration()->setMetadataCacheImpl(new ApcuCache());
|
||||
|
||||
|
||||
If you want to use one of the included core metadata drivers you
|
||||
just need to configure it. All the drivers are in the
|
||||
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
|
||||
``Doctrine\ORM\Mapping\Driver`` namespace:
|
||||
|
||||
.. code-block:: php
|
||||
@@ -54,51 +55,66 @@ Implementing Metadata Drivers
|
||||
|
||||
In addition to the included metadata drivers you can very easily
|
||||
implement your own. All you need to do is define a class which
|
||||
implements the ``Driver`` interface:
|
||||
implements the ``MappingDriver`` interface:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
|
||||
interface Driver
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Persistence\Mapping\Driver;
|
||||
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* Contract for metadata drivers.
|
||||
*/
|
||||
interface MappingDriver
|
||||
{
|
||||
/**
|
||||
* Loads the metadata for the specified class into the provided container.
|
||||
*
|
||||
* @param string $className
|
||||
* @param ClassMetadataInfo $metadata
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
function loadMetadataForClass($className, ClassMetadataInfo $metadata);
|
||||
|
||||
public function loadMetadataForClass(string $className, ClassMetadata $metadata);
|
||||
|
||||
/**
|
||||
* Gets the names of all mapped classes known to this driver.
|
||||
*
|
||||
* @return array The names of all mapped classes known to this driver.
|
||||
*/
|
||||
function getAllClassNames();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param string $className
|
||||
* @return boolean
|
||||
* @return array<int, string> The names of all mapped classes known to this driver.
|
||||
* @psalm-return list<class-string>
|
||||
*/
|
||||
function isTransient($className);
|
||||
public function getAllClassNames();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isTransient(string $className);
|
||||
}
|
||||
|
||||
If you want to write a metadata driver to parse information from
|
||||
some file format we've made your life a little easier by providing
|
||||
the ``AbstractFileDriver`` implementation for you to extend from:
|
||||
the ``FileDriver`` implementation for you to extend from:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class MyMetadataDriver extends AbstractFileDriver
|
||||
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\Driver\FileDriver;
|
||||
|
||||
class MyMetadataDriver extends FileDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -108,11 +124,11 @@ the ``AbstractFileDriver`` implementation for you to extend from:
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
$data = $this->_loadMappingFile($file);
|
||||
|
||||
// populate ClassMetadataInfo instance from $data
|
||||
// populate ClassMetadata instance from $data
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,13 +142,12 @@ the ``AbstractFileDriver`` implementation for you to extend from:
|
||||
|
||||
.. note::
|
||||
|
||||
When using the ``AbstractFileDriver`` it requires that you
|
||||
only have one entity defined per file and the file named after the
|
||||
class described inside where namespace separators are replaced by
|
||||
periods. So if you have an entity named ``Entities\User`` and you
|
||||
wanted to write a mapping file for your driver above you would need
|
||||
to name the file ``Entities.User.dcm.ext`` for it to be
|
||||
recognized.
|
||||
When using the ``FileDriver`` it requires that you only have one
|
||||
entity defined per file and the file named after the class described
|
||||
inside where namespace separators are replaced by periods. So if you
|
||||
have an entity named ``Entities\User`` and you wanted to write a
|
||||
mapping file for your driver above you would need to name the file
|
||||
``Entities.User.dcm.ext`` for it to be recognized.
|
||||
|
||||
|
||||
Now you can use your ``MyMetadataDriver`` implementation by setting
|
||||
@@ -155,14 +170,6 @@ entity when needed.
|
||||
|
||||
You have all the methods you need to manually specify the mapping
|
||||
information instead of using some mapping file to populate it from.
|
||||
The base ``ClassMetadataInfo`` class is responsible for only data
|
||||
storage and is not meant for runtime use. It does not require that
|
||||
the class actually exists yet so it is useful for describing some
|
||||
entity before it exists and using that information to generate for
|
||||
example the entities themselves. The class ``ClassMetadata``
|
||||
extends ``ClassMetadataInfo`` and adds some functionality required
|
||||
for runtime usage and requires that the PHP class is present and
|
||||
can be autoloaded.
|
||||
|
||||
You can read more about the API of the ``ClassMetadata`` classes in
|
||||
the PHP Mapping chapter.
|
||||
|
||||
@@ -9,6 +9,11 @@ the code in PHP files or inside of a static function named
|
||||
PHP Files
|
||||
---------
|
||||
|
||||
.. note::
|
||||
|
||||
PHPDriver is deprecated and will be removed in 3.0, use StaticPHPDriver
|
||||
instead.
|
||||
|
||||
If you wish to write your mapping information inside PHP files that
|
||||
are named after the entity and included to populate the metadata
|
||||
for an entity you can do so by using the ``PHPDriver``:
|
||||
@@ -180,13 +185,12 @@ It also has several methods that create builders (which are necessary for advanc
|
||||
- ``createManyToMany($name, $targetEntity)`` returns an ``ManyToManyAssociationBuilder`` instance
|
||||
- ``createOneToMany($name, $targetEntity)`` returns an ``OneToManyAssociationBuilder`` instance
|
||||
|
||||
ClassMetadataInfo API
|
||||
---------------------
|
||||
ClassMetadata API
|
||||
-----------------
|
||||
|
||||
The ``ClassMetadataInfo`` class is the base data object for storing
|
||||
the mapping metadata for a single entity. It contains all the
|
||||
getters and setters you need populate and retrieve information for
|
||||
an entity.
|
||||
The ``ClassMetadata`` class is the data object for storing the mapping
|
||||
metadata for a single entity. It contains all the getters and setters
|
||||
you need populate and retrieve information for an entity.
|
||||
|
||||
General Setters
|
||||
~~~~~~~~~~~~~~~
|
||||
@@ -304,13 +308,11 @@ Lifecycle Callback Getters
|
||||
- ``hasLifecycleCallbacks($lifecycleEvent)``
|
||||
- ``getLifecycleCallbacks($event)``
|
||||
|
||||
ClassMetadata API
|
||||
-----------------
|
||||
Runtime reflection methods
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``ClassMetadata`` class extends ``ClassMetadataInfo`` and adds
|
||||
the runtime functionality required by Doctrine. It adds a few extra
|
||||
methods related to runtime reflection for working with the entities
|
||||
themselves.
|
||||
These are methods related to runtime reflection for working with the
|
||||
entities themselves.
|
||||
|
||||
|
||||
- ``getReflectionClass()``
|
||||
|
||||
@@ -13,7 +13,7 @@ as you want, or just pick a preferred one.
|
||||
|
||||
The ``QueryBuilder`` is not an abstraction of DQL, but merely a tool to dynamically build it.
|
||||
You should still use plain DQL when you can, as it is simpler and more readable.
|
||||
More about this in the :doc:`FAQ <faq>`_.
|
||||
More about this in the :doc:`FAQ <faq>`.
|
||||
|
||||
Constructing a new QueryBuilder object
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -252,8 +252,8 @@ while the named placeholders start with a : followed by a string.
|
||||
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 PDO
|
||||
type or a DBAL Type name for conversion.
|
||||
the third argument to ``setParameter()`` explicitly. It accepts either a DBAL
|
||||
Doctrine\DBAL\ParameterType::* or a DBAL Type name for conversion.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
@@ -31,31 +31,31 @@ Each cache region resides in a specific cache namespace and has its own lifetime
|
||||
Notice that when caching collection and queries only identifiers are stored.
|
||||
The entity values will be stored in its own region
|
||||
|
||||
Something like below for an entity region :
|
||||
Something like below for an entity region:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
[
|
||||
'region_name:entity_1_hash' => ['id'=> 1, 'name' => 'FooBar', 'associationName'=>null],
|
||||
'region_name:entity_2_hash' => ['id'=> 2, 'name' => 'Foo', 'associationName'=>['id'=>11]],
|
||||
'region_name:entity_3_hash' => ['id'=> 3, 'name' => 'Bar', 'associationName'=>['id'=>22]]
|
||||
'region_name:entity_1_hash' => ['id' => 1, 'name' => 'FooBar', 'associationName' => null],
|
||||
'region_name:entity_2_hash' => ['id' => 2, 'name' => 'Foo', 'associationName' => ['id' => 11]],
|
||||
'region_name:entity_3_hash' => ['id' => 3, 'name' => 'Bar', 'associationName' => ['id' => 22]]
|
||||
];
|
||||
|
||||
|
||||
If the entity holds a collection that also needs to be cached.
|
||||
An collection region could look something like :
|
||||
An collection region could look something like:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
[
|
||||
'region_name:entity_1_coll_assoc_name_hash' => ['ownerId'=> 1, 'list' => [1, 2, 3]],
|
||||
'region_name:entity_2_coll_assoc_name_hash' => ['ownerId'=> 2, 'list' => [2, 3]],
|
||||
'region_name:entity_3_coll_assoc_name_hash' => ['ownerId'=> 3, 'list' => [2, 4]]
|
||||
'region_name:entity_1_coll_assoc_name_hash' => ['ownerId' => 1, 'list' => [1, 2, 3]],
|
||||
'region_name:entity_2_coll_assoc_name_hash' => ['ownerId' => 2, 'list' => [2, 3]],
|
||||
'region_name:entity_3_coll_assoc_name_hash' => ['ownerId' => 3, 'list' => [2, 4]]
|
||||
];
|
||||
|
||||
A query region might be something like :
|
||||
A query region might be something like:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -93,8 +93,6 @@ Cache region
|
||||
``Doctrine\ORM\Cache\Region`` defines a contract for accessing a particular
|
||||
cache region.
|
||||
|
||||
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/Region.html>`_.
|
||||
|
||||
Concurrent cache region
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -105,8 +103,6 @@ If you want to use an ``READ_WRITE`` cache, you should consider providing your o
|
||||
|
||||
``Doctrine\ORM\Cache\ConcurrentRegion`` defines a contract for concurrently managed data region.
|
||||
|
||||
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/ConcurrentRegion.html>`_.
|
||||
|
||||
Timestamp region
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -114,8 +110,6 @@ Timestamp region
|
||||
|
||||
Tracks the timestamps of the most recent updates to particular entity.
|
||||
|
||||
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/TimestampRegion.html>`_.
|
||||
|
||||
.. _reference-second-level-cache-mode:
|
||||
|
||||
Caching mode
|
||||
@@ -132,7 +126,7 @@ Caching mode
|
||||
|
||||
* Read Write Cache doesn’t employ any locks but can do reads, inserts, updates and deletes.
|
||||
* Good if the application needs to update data rarely.
|
||||
|
||||
|
||||
|
||||
* ``READ_WRITE``
|
||||
|
||||
@@ -147,21 +141,21 @@ Built-in cached persisters
|
||||
|
||||
Cached persisters are responsible to access cache regions.
|
||||
|
||||
+-----------------------+-------------------------------------------------------------------------------------------+
|
||||
| Cache Usage | Persister |
|
||||
+=======================+===========================================================================================+
|
||||
| READ_ONLY | Doctrine\\ORM\\Cache\\Persister\\Entity\\ReadOnlyCachedEntityPersister |
|
||||
+-----------------------+-------------------------------------------------------------------------------------------+
|
||||
| READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Entity\\ReadWriteCachedEntityPersister |
|
||||
+-----------------------+-------------------------------------------------------------------------------------------+
|
||||
| NONSTRICT_READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Entity\\NonStrictReadWriteCachedEntityPersister |
|
||||
+-----------------------+-------------------------------------------------------------------------------------------+
|
||||
| READ_ONLY | Doctrine\\ORM\\Cache\\Persister\\Collection\\ReadOnlyCachedCollectionPersister |
|
||||
+-----------------------+-------------------------------------------------------------------------------------------+
|
||||
| READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Collection\\ReadWriteCachedCollectionPersister |
|
||||
+-----------------------+-------------------------------------------------------------------------------------------+
|
||||
| NONSTRICT_READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Collection\\NonStrictReadWriteCachedCollectionPersister |
|
||||
+-----------------------+-------------------------------------------------------------------------------------------+
|
||||
+-----------------------+------------------------------------------------------------------------------------------+
|
||||
| Cache Usage | Persister |
|
||||
+=======================+==========================================================================================+
|
||||
| READ_ONLY | ``Doctrine\ORM\Cache\Persister\Entity\ReadOnlyCachedEntityPersister`` |
|
||||
+-----------------------+------------------------------------------------------------------------------------------+
|
||||
| READ_WRITE | ``Doctrine\ORM\Cache\Persister\Entity\ReadWriteCachedEntityPersister`` |
|
||||
+-----------------------+------------------------------------------------------------------------------------------+
|
||||
| NONSTRICT_READ_WRITE | ``Doctrine\ORM\Cache\Persister\Entity\NonStrictReadWriteCachedEntityPersister`` |
|
||||
+-----------------------+------------------------------------------------------------------------------------------+
|
||||
| READ_ONLY | ``Doctrine\ORM\Cache\Persister\Collection\ReadOnlyCachedCollectionPersister`` |
|
||||
+-----------------------+------------------------------------------------------------------------------------------+
|
||||
| READ_WRITE | ``Doctrine\ORM\Cache\Persister\Collection\ReadWriteCachedCollectionPersister`` |
|
||||
+-----------------------+------------------------------------------------------------------------------------------+
|
||||
| NONSTRICT_READ_WRITE | ``Doctrine\ORM\Cache\Persister\Collection\NonStrictReadWriteCachedCollectionPersister`` |
|
||||
+-----------------------+------------------------------------------------------------------------------------------+
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
@@ -172,13 +166,13 @@ Enable Second Level Cache
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To enable the second-level-cache, you should provide a cache factory.
|
||||
``\Doctrine\ORM\Cache\DefaultCacheFactory`` is the default implementation.
|
||||
``Doctrine\ORM\Cache\DefaultCacheFactory`` is the default implementation.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/** @var \Doctrine\ORM\Cache\RegionsConfiguration $cacheConfig */
|
||||
/** @var \Doctrine\Common\Cache\Cache $cache */
|
||||
/** @var \Psr\Cache\CacheItemPoolInterface $cache */
|
||||
/** @var \Doctrine\ORM\Configuration $config */
|
||||
|
||||
$factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($cacheConfig, $cache);
|
||||
@@ -196,7 +190,7 @@ Cache Factory
|
||||
|
||||
Cache Factory is the main point of extension.
|
||||
|
||||
It allows you to provide a specific implementation of the following components :
|
||||
It allows you to provide a specific implementation of the following components:
|
||||
|
||||
``QueryCache``
|
||||
stores and retrieves query cache results.
|
||||
@@ -209,8 +203,6 @@ It allows you to provide a specific implementation of the following components :
|
||||
``CollectionHydrator``
|
||||
transforms collections into cache entries and cache entries into collections
|
||||
|
||||
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/DefaultCacheFactory.html>`_.
|
||||
|
||||
Region Lifetime
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -234,12 +226,12 @@ Cache Log
|
||||
~~~~~~~~~
|
||||
By providing a cache logger you should be able to get information about all cache operations such as hits, misses and puts.
|
||||
|
||||
``\Doctrine\ORM\Cache\Logging\StatisticsCacheLogger`` is a built-in implementation that provides basic statistics.
|
||||
``Doctrine\ORM\Cache\Logging\StatisticsCacheLogger`` is a built-in implementation that provides basic statistics.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/* @var $config \Doctrine\ORM\Configuration */
|
||||
/** @var \Doctrine\ORM\Configuration $config */
|
||||
$logger = new \Doctrine\ORM\Cache\Logging\StatisticsCacheLogger();
|
||||
|
||||
// Cache logger
|
||||
@@ -269,12 +261,9 @@ By providing a cache logger you should be able to get information about all cach
|
||||
$logger->getMissCount();
|
||||
|
||||
If you want to get more information you should implement
|
||||
``\Doctrine\ORM\Cache\Logging\CacheLogger`` and collect
|
||||
``Doctrine\ORM\Cache\Logging\CacheLogger`` and collect
|
||||
all the information you want.
|
||||
|
||||
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/Logging/CacheLogger.html>`_.
|
||||
|
||||
|
||||
Entity cache definition
|
||||
-----------------------
|
||||
* Entity cache configuration allows you to define the caching strategy and region for an entity.
|
||||
@@ -330,8 +319,8 @@ level cache region.
|
||||
Country:
|
||||
type: entity
|
||||
cache:
|
||||
usage : READ_ONLY
|
||||
region : my_entity_region
|
||||
usage: READ_ONLY
|
||||
region: my_entity_region
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
@@ -401,7 +390,7 @@ It caches the primary keys of association and cache each element will be cached
|
||||
</id>
|
||||
|
||||
<field name="name" type="string" column="name"/>
|
||||
|
||||
|
||||
<many-to-one field="country" target-entity="Country">
|
||||
<cache usage="NONSTRICT_READ_WRITE" />
|
||||
|
||||
@@ -421,7 +410,7 @@ It caches the primary keys of association and cache each element will be cached
|
||||
State:
|
||||
type: entity
|
||||
cache:
|
||||
usage : NONSTRICT_READ_WRITE
|
||||
usage: NONSTRICT_READ_WRITE
|
||||
id:
|
||||
id:
|
||||
type: integer
|
||||
@@ -439,17 +428,18 @@ It caches the primary keys of association and cache each element will be cached
|
||||
country_id:
|
||||
referencedColumnName: id
|
||||
cache:
|
||||
usage : NONSTRICT_READ_WRITE
|
||||
usage: NONSTRICT_READ_WRITE
|
||||
|
||||
oneToMany:
|
||||
cities:
|
||||
targetEntity:City
|
||||
mappedBy: state
|
||||
cache:
|
||||
usage : NONSTRICT_READ_WRITE
|
||||
usage: NONSTRICT_READ_WRITE
|
||||
|
||||
.. note::
|
||||
|
||||
> Note: for this to work, the target entity must also be marked as cacheable.
|
||||
for this to work, the target entity must also be marked as cacheable.
|
||||
|
||||
Cache usage
|
||||
~~~~~~~~~~~
|
||||
@@ -466,8 +456,8 @@ Basic entity cache
|
||||
|
||||
$country1 = $em->find('Country', 1); // Retrieve item from cache
|
||||
|
||||
$country1->setName("New Name");
|
||||
|
||||
$country1->setName('New Name');
|
||||
|
||||
$em->flush(); // Hit database to update the row and update cache
|
||||
|
||||
$em->clear(); // Clear entity manager
|
||||
@@ -492,7 +482,7 @@ Association cache
|
||||
$state = $em->find('State', 1);
|
||||
|
||||
// Hit database to update the row and update cache entry
|
||||
$state->setName("New Name");
|
||||
$state->setName('New Name');
|
||||
$em->persist($state);
|
||||
$em->flush();
|
||||
|
||||
@@ -543,14 +533,14 @@ The query cache stores the results of the query but as identifiers, entity value
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/* @var $em \Doctrine\ORM\EntityManager */
|
||||
/** @var \Doctrine\ORM\EntityManager $em */
|
||||
|
||||
// Execute database query, store query cache and entity cache
|
||||
$result1 = $em->createQuery('SELECT c FROM Country c ORDER BY c.name')
|
||||
->setCacheable(true)
|
||||
->getResult();
|
||||
|
||||
$em->clear()
|
||||
$em->clear();
|
||||
|
||||
// Check if query result is valid and load entities from cache
|
||||
$result2 = $em->createQuery('SELECT c FROM Country c ORDER BY c.name')
|
||||
@@ -570,16 +560,16 @@ The Cache Mode controls how a particular query interacts with the second-level c
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/* @var $em \Doctrine\ORM\EntityManager */
|
||||
/** @var \Doctrine\ORM\EntityManager $em */
|
||||
// Will refresh the query cache and all entities the cache as it reads from the database.
|
||||
$result1 = $em->createQuery('SELECT c FROM Country c ORDER BY c.name')
|
||||
->setCacheMode(Cache::MODE_GET)
|
||||
->setCacheMode(\Doctrine\ORM\Cache::MODE_GET)
|
||||
->setCacheable(true)
|
||||
->getResult();
|
||||
|
||||
.. note::
|
||||
|
||||
The the default query cache mode is ```Cache::MODE_NORMAL```
|
||||
The default query cache mode is ```Cache::MODE_NORMAL```
|
||||
|
||||
DELETE / UPDATE queries
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -597,7 +587,7 @@ Execute the ``UPDATE`` and invalidate ``all cache entries`` using ``Query::HINT_
|
||||
<?php
|
||||
// Execute and invalidate
|
||||
$this->_em->createQuery("UPDATE Entity\Country u SET u.name = 'unknown' WHERE u.id = 1")
|
||||
->setHint(Query::HINT_CACHE_EVICT, true)
|
||||
->setHint(\Doctrine\ORM\Query::HINT_CACHE_EVICT, true)
|
||||
->execute();
|
||||
|
||||
|
||||
@@ -659,7 +649,7 @@ However, you can use the cache API to check / invalidate cache entries.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
/* @var $cache \Doctrine\ORM\Cache */
|
||||
/** @var \Doctrine\ORM\Cache $cache */
|
||||
$cache = $em->getCache();
|
||||
|
||||
$cache->containsEntity('Entity\State', 1) // Check if the cache exists
|
||||
@@ -704,19 +694,19 @@ For performance reasons the cache API does not extract from composite primary ke
|
||||
}
|
||||
|
||||
// Supported
|
||||
/* @var $article Article */
|
||||
/** @var Article $article */
|
||||
$article = $em->find('Article', 1);
|
||||
|
||||
// Supported
|
||||
/* @var $article Article */
|
||||
/** @var Article $article */
|
||||
$article = $em->find('Article', $article);
|
||||
|
||||
// Supported
|
||||
$id = array('source' => 1, 'target' => 2);
|
||||
$id = ['source' => 1, 'target' => 2];
|
||||
$reference = $em->find('Reference', $id);
|
||||
|
||||
// NOT Supported
|
||||
$id = array('source' => new Article(1), 'target' => new Article(2));
|
||||
$id = ['source' => new Article(1), 'target' => new Article(2)];
|
||||
$reference = $em->find('Reference', $id);
|
||||
|
||||
Distributed environments
|
||||
|
||||
@@ -7,24 +7,10 @@ Doctrine Console
|
||||
The Doctrine Console is a Command Line Interface tool for simplifying common
|
||||
administration tasks during the development of a project that uses ORM.
|
||||
|
||||
Take a look at the :doc:`Installation and Configuration <configuration>`
|
||||
chapter for more information how to setup the console command.
|
||||
For the following examples, we will set up the CLI as ``bin/doctrine``.
|
||||
|
||||
Display Help Information
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Type ``php vendor/bin/doctrine`` on the command line and you should see an
|
||||
overview of the available commands or use the --help flag to get
|
||||
information on the available commands. If you want to know more
|
||||
about the use of generate entities for example, you can call:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$> php vendor/bin/doctrine orm:generate-entities --help
|
||||
|
||||
|
||||
Configuration
|
||||
~~~~~~~~~~~~~
|
||||
Setting Up the Console
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Whenever the ``doctrine`` command line tool is invoked, it can
|
||||
access all Commands that were registered by a developer. There is no
|
||||
@@ -34,25 +20,33 @@ Doctrine DBAL and ORM. If you want to use additional commands you
|
||||
have to register them yourself.
|
||||
|
||||
All the commands of the Doctrine Console require access to the
|
||||
``EntityManager``. You have to inject it into the console application with
|
||||
``ConsoleRunner::createHelperSet``. Whenever you invoke the Doctrine
|
||||
binary, it searches the current directory for the file ``cli-config.php``.
|
||||
This file contains the project-specific configuration.
|
||||
``EntityManager``. You have to inject it into the console application.
|
||||
|
||||
Here is an example of a the project-specific ``cli-config.php``:
|
||||
Here is an example of a the project-specific ``bin/doctrine`` binary.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
||||
|
||||
// replace this with the path to your own project bootstrap file.
|
||||
use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
|
||||
// replace with path to your own project bootstrap file
|
||||
require_once 'bootstrap.php';
|
||||
|
||||
// replace with mechanism to retrieve EntityManager in your app
|
||||
$entityManager = GetEntityManager();
|
||||
|
||||
return ConsoleRunner::createHelperSet($entityManager);
|
||||
$commands = [
|
||||
// If you want to add your own custom console commands,
|
||||
// you can do so here.
|
||||
];
|
||||
|
||||
ConsoleRunner::run(
|
||||
new SingleManagerProvider($entityManager),
|
||||
$commands
|
||||
);
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -60,6 +54,18 @@ Here is an example of a the project-specific ``cli-config.php``:
|
||||
and use their facilities to access the Doctrine EntityManager and
|
||||
Connection Resources.
|
||||
|
||||
Display Help Information
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Type ``php bin/doctrine`` on the command line and you should see an
|
||||
overview of the available commands or use the ``--help`` flag to get
|
||||
information on the available commands. If you want to know more
|
||||
about the use of generate entities for example, you can call:
|
||||
|
||||
::
|
||||
|
||||
$> php bin/doctrine orm:generate-entities --help
|
||||
|
||||
Command Overview
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -143,7 +149,7 @@ When using the SchemaTool class directly, create your schema using
|
||||
the ``createSchema()`` method. First create an instance of the
|
||||
``SchemaTool`` and pass it an instance of the ``EntityManager``
|
||||
that you want to use to create the schema. This method receives an
|
||||
array of ``ClassMetadataInfo`` instances.
|
||||
array of ``ClassMetadata`` instances.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -174,8 +180,8 @@ tables of the current model to clean up with orphaned tables.
|
||||
|
||||
You can also use database introspection to update your schema
|
||||
easily with the ``updateSchema()`` method. It will compare your
|
||||
existing database schema to the passed array of
|
||||
``ClassMetadataInfo`` instances.
|
||||
existing database schema to the passed array of ``ClassMetadata``
|
||||
instances.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -189,38 +195,35 @@ To create the schema use the ``create`` command:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php doctrine orm:schema-tool:create
|
||||
$ php bin/doctrine orm:schema-tool:create
|
||||
|
||||
To drop the schema use the ``drop`` command:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php doctrine orm:schema-tool:drop
|
||||
$ php bin/doctrine orm:schema-tool:drop
|
||||
|
||||
If you want to drop and then recreate the schema then use both
|
||||
options:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php doctrine orm:schema-tool:drop
|
||||
$ php doctrine orm:schema-tool:create
|
||||
$ php bin/doctrine orm:schema-tool:drop
|
||||
$ php bin/doctrine orm:schema-tool:create
|
||||
|
||||
As you would think, if you want to update your schema use the
|
||||
``update`` command:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php doctrine orm:schema-tool:update
|
||||
$ php bin/doctrine orm:schema-tool:update
|
||||
|
||||
All of the above commands also accept a ``--dump-sql`` option that
|
||||
will output the SQL for the ran operation.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php doctrine orm:schema-tool:create --dump-sql
|
||||
|
||||
Before using the orm:schema-tool commands, remember to configure
|
||||
your cli-config.php properly.
|
||||
$ php bin/doctrine orm:schema-tool:create --dump-sql
|
||||
|
||||
Entity Generation
|
||||
-----------------
|
||||
@@ -229,9 +232,9 @@ Generate entity classes and method stubs from your mapping information.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php doctrine orm:generate-entities
|
||||
$ php doctrine orm:generate-entities --update-entities
|
||||
$ php doctrine orm:generate-entities --regenerate-entities
|
||||
$ php bin/doctrine orm:generate-entities
|
||||
$ php bin/doctrine orm:generate-entities --update-entities
|
||||
$ php bin/doctrine orm:generate-entities --regenerate-entities
|
||||
|
||||
This command is not suited for constant usage. It is a little helper and does
|
||||
not support all the mapping edge cases very well. You still have to put work
|
||||
@@ -316,14 +319,14 @@ convert to and the path to generate it:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php doctrine orm:convert-mapping xml /path/to/mapping-path-converted-to-xml
|
||||
$ php bin/doctrine orm:convert-mapping xml /path/to/mapping-path-converted-to-xml
|
||||
|
||||
Reverse Engineering
|
||||
-------------------
|
||||
|
||||
You can use the ``DatabaseDriver`` to reverse engineer a database
|
||||
to an array of ``ClassMetadataInfo`` instances and generate YAML,
|
||||
XML, etc. from them.
|
||||
You can use the ``DatabaseDriver`` to reverse engineer a database to an
|
||||
array of ``ClassMetadata`` instances and generate YAML, XML, etc. from
|
||||
them.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -366,7 +369,7 @@ You can also reverse engineer a database using the
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$ php doctrine orm:convert-mapping --from-database yml /path/to/mapping-path-converted-to-yml
|
||||
$ php bin/doctrine orm:convert-mapping --from-database yml /path/to/mapping-path-converted-to-yml
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -393,6 +396,11 @@ You can either use the Doctrine Command Line Tool:
|
||||
|
||||
doctrine orm:validate-schema
|
||||
|
||||
If the validation fails, you can change the verbosity level to
|
||||
check the detected errors:
|
||||
|
||||
doctrine orm:validate-schema -v
|
||||
|
||||
Or you can trigger the validation manually:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -521,6 +521,8 @@ For each cascade operation that gets activated, Doctrine also
|
||||
applies that operation to the association, be it single or
|
||||
collection valued.
|
||||
|
||||
.. _persistence-by-reachability:
|
||||
|
||||
Persistence by Reachability: Cascade Persist
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ Work that have not yet been persisted are lost.
|
||||
|
||||
.. note::
|
||||
|
||||
Doctrine does NEVER touch the public API of methods in your entity
|
||||
Doctrine NEVER touches the public API of methods in your entity
|
||||
classes (like getters and setters) nor the constructor method.
|
||||
Instead, it uses reflection to get/set data from/to your entity objects.
|
||||
When Doctrine fetches data from DB and saves it back,
|
||||
|
||||
@@ -256,6 +256,11 @@ Optional attributes:
|
||||
table? Defaults to false.
|
||||
- nullable - Should this field allow NULL as a value? Defaults to
|
||||
false.
|
||||
- insertable - Should this field be inserted? Defaults to true.
|
||||
- updatable - Should this field be updated? Defaults to true.
|
||||
- generated - Enum of the values ALWAYS, INSERT, NEVER that determines if
|
||||
generated value must be fetched from database after INSERT or UPDATE.
|
||||
Defaults to "NEVER".
|
||||
- version - Should this field be used for optimistic locking? Only
|
||||
works on fields with type integer or datetime.
|
||||
- scale - Scale of a decimal type.
|
||||
@@ -689,6 +694,7 @@ specified by their respective tags:
|
||||
- ``<cascade-merge />``
|
||||
- ``<cascade-remove />``
|
||||
- ``<cascade-refresh />``
|
||||
- ``<cascade-detach />``
|
||||
|
||||
Join Column Element
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -40,7 +40,7 @@ easily using a combination of ``count`` and ``slice``.
|
||||
``removeElement`` directly issued DELETE queries to the database from
|
||||
version 2.4.0 to 2.7.0. This circumvents the flush operation and might run
|
||||
outside a transactional boundary if you don't create one yourself. We
|
||||
consider this a critical bug in the assumptio of how the ORM works and
|
||||
consider this a critical bug in the assumption of how the ORM works and
|
||||
reverted ``removeElement`` EXTRA_LAZY behavior in 2.7.1.
|
||||
|
||||
|
||||
|
||||
@@ -81,9 +81,11 @@ that directory with the following contents:
|
||||
|
||||
{
|
||||
"require": {
|
||||
"doctrine/orm": "^2.6.2",
|
||||
"symfony/yaml": "2.*",
|
||||
"symfony/cache": "^5.3"
|
||||
"doctrine/orm": "^2.11.0",
|
||||
"doctrine/dbal": "^3.2",
|
||||
"doctrine/annotations": "1.13.2",
|
||||
"symfony/yaml": "^5.4",
|
||||
"symfony/cache": "^5.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {"": "src/"}
|
||||
@@ -112,6 +114,14 @@ Add the following directories:
|
||||
.. note::
|
||||
The YAML driver is deprecated and will be removed in version 3.0.
|
||||
It is strongly recommended to switch to one of the other mappings.
|
||||
.. note::
|
||||
It is strongly recommended that you require ``doctrine/dbal`` in your
|
||||
``composer.json`` as well, because using the ORM means mapping objects
|
||||
and their fields to database tables and their columns, and that
|
||||
requires mentioning so-called types that are defined in ``doctrine/dbal``
|
||||
in your application. Having an explicit requirement means you control
|
||||
when the upgrade to the next major version happens, so that you can
|
||||
do the necessary changes in your application beforehand.
|
||||
|
||||
Obtaining the EntityManager
|
||||
---------------------------
|
||||
@@ -127,8 +137,8 @@ step:
|
||||
|
||||
<?php
|
||||
// bootstrap.php
|
||||
use Doctrine\ORM\Tools\Setup;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\ORMSetup;
|
||||
|
||||
require_once "vendor/autoload.php";
|
||||
|
||||
@@ -137,10 +147,10 @@ step:
|
||||
$proxyDir = null;
|
||||
$cache = null;
|
||||
$useSimpleAnnotationReader = false;
|
||||
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/src"), $isDevMode, $proxyDir, $cache, $useSimpleAnnotationReader);
|
||||
// or if you prefer yaml or XML
|
||||
// $config = Setup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode);
|
||||
// $config = Setup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode);
|
||||
$config = ORMSetup::createAnnotationMetadataConfiguration(array(__DIR__."/src"), $isDevMode, $proxyDir, $cache, $useSimpleAnnotationReader);
|
||||
// or if you prefer YAML or XML
|
||||
// $config = ORMSetup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode);
|
||||
// $config = ORMSetup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode);
|
||||
|
||||
// database configuration parameters
|
||||
$conn = array(
|
||||
@@ -163,7 +173,7 @@ The ``require_once`` statement sets up the class autoloading for Doctrine and
|
||||
its dependencies using Composer's autoloader.
|
||||
|
||||
The second block consists of the instantiation of the ORM
|
||||
``Configuration`` object using the Setup helper. It assumes a bunch
|
||||
``Configuration`` object using the ``ORMSetup`` helper. It assumes a bunch
|
||||
of defaults that you don't have to bother about for now. You can
|
||||
read up on the configuration details in the
|
||||
:doc:`reference chapter on configuration <../reference/configuration>`.
|
||||
@@ -181,22 +191,35 @@ Generating the Database Schema
|
||||
|
||||
Doctrine has a command-line interface that allows you to access the SchemaTool,
|
||||
a component that can generate a relational database schema based entirely on the
|
||||
defined entity classes and their metadata. For this tool to work, a
|
||||
``cli-config.php`` file must exist in the project root directory:
|
||||
defined entity classes and their metadata. For this tool to work, you need to
|
||||
create an executable console script as described in the
|
||||
:doc:`tools chapter <../reference/tools>`.
|
||||
|
||||
If you created the ``bootstrap.php`` file as described in the previous section,
|
||||
that script could look like this:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
// cli-config.php
|
||||
require_once "bootstrap.php";
|
||||
// bin/doctrine
|
||||
|
||||
return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($entityManager);
|
||||
use Doctrine\ORM\Tools\Console\ConsoleRunner;
|
||||
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
|
||||
|
||||
Now call the Doctrine command-line tool:
|
||||
// Adjust this path to your actual bootstrap.php
|
||||
require __DIR__ . 'path/to/your/bootstrap.php';
|
||||
|
||||
ConsoleRunner::run(
|
||||
new SingleManagerProvider($entityManager)
|
||||
);
|
||||
|
||||
In the following examples, we will assume that this script has been created as
|
||||
``bin/doctrine``.
|
||||
|
||||
::
|
||||
|
||||
$ vendor/bin/doctrine orm:schema-tool:create
|
||||
$ php bin/doctrine orm:schema-tool:create
|
||||
|
||||
Since we haven't added any entity metadata in ``src`` yet, you'll see a message
|
||||
stating "No Metadata Classes to process." In the next section, we'll create a
|
||||
@@ -208,14 +231,14 @@ You can easily recreate the database using the following commands:
|
||||
|
||||
::
|
||||
|
||||
$ vendor/bin/doctrine orm:schema-tool:drop --force
|
||||
$ vendor/bin/doctrine orm:schema-tool:create
|
||||
$ php bin/doctrine orm:schema-tool:drop --force
|
||||
$ php bin/doctrine orm:schema-tool:create
|
||||
|
||||
Or you can use the update functionality:
|
||||
|
||||
::
|
||||
|
||||
$ vendor/bin/doctrine orm:schema-tool:update --force
|
||||
$ php bin/doctrine orm:schema-tool:update --force
|
||||
|
||||
The updating of databases uses a diff algorithm for a given
|
||||
database schema. This is a cornerstone of the ``Doctrine\DBAL`` package,
|
||||
@@ -561,7 +584,7 @@ let's update the database schema:
|
||||
|
||||
::
|
||||
|
||||
$ vendor/bin/doctrine orm:schema-tool:update --force --dump-sql
|
||||
$ php bin/doctrine orm:schema-tool:update --force --dump-sql
|
||||
|
||||
Specifying both flags ``--force`` and ``--dump-sql`` will cause the DDL
|
||||
statements to be executed and then printed to the screen.
|
||||
@@ -642,7 +665,7 @@ Let's continue by creating a script to display the name of a product based on it
|
||||
echo sprintf("-%s\n", $product->getName());
|
||||
|
||||
Next we'll update a product's name, given its id. This simple example will
|
||||
help demonstrate Doctrine's implementation of the UnitOfWork pattern. Doctrine
|
||||
help demonstrate Doctrine's implementation of the :ref:`UnitOfWork pattern <unit-of-work>`. Doctrine
|
||||
keeps track of all the entities that were retrieved from the Entity Manager,
|
||||
and can detect when any of those entities' properties have been modified.
|
||||
As a result, rather than needing to call ``persist($entity)`` for each individual
|
||||
@@ -1258,7 +1281,7 @@ class that holds the owning sides.
|
||||
Update your database schema by running:
|
||||
::
|
||||
|
||||
$ vendor/bin/doctrine orm:schema-tool:update --force
|
||||
$ php bin/doctrine orm:schema-tool:update --force
|
||||
|
||||
|
||||
Implementing more Requirements
|
||||
@@ -1334,7 +1357,7 @@ call this script as follows:
|
||||
php create_bug.php 1 1 1
|
||||
|
||||
See how simple it is to relate a Bug, Reporter, Engineer and Products?
|
||||
Also recall that thanks to the UnitOfWork pattern, Doctrine will detect
|
||||
Also recall that thanks to the :ref:`UnitOfWork pattern <unit-of-work>`, Doctrine will detect
|
||||
these relations and update all of the modified entities in the database
|
||||
automatically when ``flush()`` is called.
|
||||
|
||||
|
||||
@@ -14,25 +14,25 @@
|
||||
|
||||
<xs:element name="doctrine-mapping">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="mapped-superclass" type="orm:mapped-superclass" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="entity" type="orm:entity" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="embeddable" type="orm:embeddable" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:complexType name="emptyType">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="cascade-type">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="cascade-all" type="orm:emptyType" minOccurs="0"/>
|
||||
<xs:element name="cascade-persist" type="orm:emptyType" minOccurs="0"/>
|
||||
<xs:element name="cascade-merge" type="orm:emptyType" minOccurs="0"/>
|
||||
@@ -40,7 +40,7 @@
|
||||
<xs:element name="cascade-refresh" type="orm:emptyType" minOccurs="0"/>
|
||||
<xs:element name="cascade-detach" type="orm:emptyType" minOccurs="0"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
@@ -66,19 +66,19 @@
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="lifecycle-callback">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="type" type="orm:lifecycle-callback-type" use="required" />
|
||||
<xs:attribute name="method" type="xs:NMTOKEN" use="required" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="lifecycle-callbacks">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="lifecycle-callback" type="orm:lifecycle-callback" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
@@ -96,34 +96,34 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="named-native-query">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="query" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:string" use="required" />
|
||||
<xs:attribute name="result-class" type="orm:fqcn" />
|
||||
<xs:attribute name="result-set-mapping" type="xs:string" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="named-native-queries">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="named-native-query" type="orm:named-native-query" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="entity-listener">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="lifecycle-callback" type="orm:lifecycle-callback" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="class" type="orm:fqcn"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="entity-listeners">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="entity-listener" type="orm:entity-listener" minOccurs="1" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="column-result">
|
||||
@@ -136,29 +136,29 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="entity-result">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="field-result" type="orm:field-result" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="entity-class" type="orm:fqcn" use="required" />
|
||||
<xs:attribute name="discriminator-column" type="xs:string" use="optional" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="sql-result-set-mapping">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="entity-result" type="orm:entity-result"/>
|
||||
<xs:element name="column-result" type="orm:column-result"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:string" use="required" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="sql-result-set-mappings">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="sql-result-set-mapping" type="orm:sql-result-set-mapping" minOccurs="1" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="cache">
|
||||
@@ -208,28 +208,28 @@
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="option" mixed="true">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="option" type="orm:option"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required"/>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="options">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="option" type="orm:option" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="mapped-superclass" >
|
||||
<xs:complexContent>
|
||||
<xs:extension base="orm:entity">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
@@ -238,9 +238,9 @@
|
||||
<xs:complexType name="embeddable">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="orm:entity">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
@@ -264,7 +264,6 @@
|
||||
<xs:simpleType name="generator-strategy">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="NONE"/>
|
||||
<xs:enumeration value="TABLE"/>
|
||||
<xs:enumeration value="SEQUENCE"/>
|
||||
<xs:enumeration value="IDENTITY"/>
|
||||
<xs:enumeration value="AUTO"/>
|
||||
@@ -289,17 +288,29 @@
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="generated-type">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="NEVER"/>
|
||||
<xs:enumeration value="INSERT"/>
|
||||
<xs:enumeration value="ALWAYS"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="field">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
|
||||
<xs:attribute name="column" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="unique" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="nullable" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="insertable" type="xs:boolean" default="true" />
|
||||
<xs:attribute name="updatable" type="xs:boolean" default="true" />
|
||||
<xs:attribute name="generated" type="orm:generated-type" default="NEVER" />
|
||||
<xs:attribute name="enum-type" type="xs:string" />
|
||||
<xs:attribute name="version" type="xs:boolean" />
|
||||
<xs:attribute name="column-definition" type="xs:string" />
|
||||
<xs:attribute name="precision" type="xs:integer" use="optional" />
|
||||
@@ -308,6 +319,9 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="embedded">
|
||||
<xs:sequence>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:string" use="required" />
|
||||
<xs:attribute name="class" type="orm:fqcn" use="optional" />
|
||||
<xs:attribute name="column-prefix" type="xs:string" use="optional" />
|
||||
@@ -315,9 +329,9 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="discriminator-column">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN"/>
|
||||
<xs:attribute name="field-name" type="xs:NMTOKEN" />
|
||||
@@ -327,10 +341,10 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="unique-constraint">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="optional"/>
|
||||
<xs:attribute name="columns" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="fields" type="xs:string" use="optional"/>
|
||||
@@ -338,69 +352,69 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="unique-constraints">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="unique-constraint" type="orm:unique-constraint" minOccurs="1" maxOccurs="unbounded"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="index">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="optional"/>
|
||||
<xs:attribute name="columns" type="xs:string" use="required"/>
|
||||
<xs:attribute name="columns" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="fields" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="flags" type="xs:string" use="optional"/>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="indexes">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="index" type="orm:index" minOccurs="1" maxOccurs="unbounded"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="discriminator-mapping">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="value" type="xs:NMTOKEN" use="required"/>
|
||||
<xs:attribute name="class" type="orm:fqcn" use="required"/>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="discriminator-map">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="discriminator-mapping" type="orm:discriminator-mapping" minOccurs="1" maxOccurs="unbounded"/>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="generator">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="strategy" type="orm:generator-strategy" use="optional" default="AUTO" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="id">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="generator" type="orm:generator" minOccurs="0" />
|
||||
<xs:element name="sequence-generator" type="orm:sequence-generator" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="custom-id-generator" type="orm:custom-id-generator" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="column" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="association-key" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="column-definition" type="xs:string" />
|
||||
@@ -408,9 +422,9 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="sequence-generator">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="sequence-name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="allocation-size" type="xs:integer" use="optional" default="1" />
|
||||
<xs:attribute name="initial-value" type="xs:integer" use="optional" default="1" />
|
||||
@@ -418,9 +432,9 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="custom-id-generator">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="class" type="orm:fqcn" use="required" />
|
||||
</xs:complexType>
|
||||
|
||||
@@ -432,17 +446,17 @@
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="inverse-join-columns">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="join-column">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="optional" />
|
||||
<xs:attribute name="referenced-column-name" type="xs:NMTOKEN" use="optional" default="id" />
|
||||
<xs:attribute name="unique" type="xs:boolean" default="false" />
|
||||
@@ -453,36 +467,36 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="join-columns">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="join-table">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="join-columns" type="orm:join-columns" />
|
||||
<xs:element name="inverse-join-columns" type="orm:join-columns" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="schema" type="xs:NMTOKEN" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="order-by">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="order-by-field" type="orm:order-by-field" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="order-by-field">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="direction" type="orm:order-by-direction" default="ASC" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
@@ -495,14 +509,20 @@
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="columntoken" id="columntoken">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:pattern value="[-._:A-Za-z0-9`]+" id="columntoken.pattern"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="many-to-many">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="cache" type="orm:cache" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="cascade" type="orm:cascade-type" minOccurs="0" />
|
||||
<xs:element name="join-table" type="orm:join-table" minOccurs="0" />
|
||||
<xs:element name="order-by" type="orm:order-by" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="target-entity" type="xs:string" use="required" />
|
||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
|
||||
@@ -514,12 +534,12 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="one-to-many">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="cache" type="orm:cache" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="cascade" type="orm:cascade-type" minOccurs="0" />
|
||||
<xs:element name="order-by" type="orm:order-by" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="target-entity" type="xs:string" use="required" />
|
||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" use="required" />
|
||||
@@ -530,7 +550,7 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="many-to-one">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="cache" type="orm:cache" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="cascade" type="orm:cascade-type" minOccurs="0" />
|
||||
<xs:choice minOccurs="0" maxOccurs="1">
|
||||
@@ -539,7 +559,7 @@
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="target-entity" type="xs:string" />
|
||||
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
|
||||
@@ -548,7 +568,7 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="one-to-one">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="cache" type="orm:cache" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="cascade" type="orm:cascade-type" minOccurs="0" />
|
||||
<xs:choice minOccurs="0" maxOccurs="1">
|
||||
@@ -557,7 +577,7 @@
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="target-entity" type="xs:string" />
|
||||
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
|
||||
@@ -568,19 +588,19 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="association-overrides">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="association-override" type="orm:association-override" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="association-override">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="join-table" type="orm:join-table" minOccurs="0" />
|
||||
<xs:element name="join-columns" type="orm:join-columns" minOccurs="0" />
|
||||
<xs:element name="inversed-by" type="orm:inversed-by-override" minOccurs="0" maxOccurs="1" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="fetch" type="orm:fetch-type" use="optional" />
|
||||
</xs:complexType>
|
||||
@@ -590,30 +610,32 @@
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="attribute-overrides">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="attribute-override" type="orm:attribute-override" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="attribute-override">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="field" type="orm:attribute-override-field" minOccurs="1" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="attribute-override-field">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:sequence>
|
||||
</xs:choice>
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
|
||||
<xs:attribute name="column" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="unique" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="nullable" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="insertable" type="xs:boolean" default="true" />
|
||||
<xs:attribute name="updateable" type="xs:boolean" default="true" />
|
||||
<xs:attribute name="version" type="xs:boolean" />
|
||||
<xs:attribute name="column-definition" type="xs:string" />
|
||||
<xs:attribute name="precision" type="xs:integer" use="optional" />
|
||||
|
||||
@@ -1,31 +1,20 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use BackedEnum;
|
||||
use Countable;
|
||||
use Doctrine\Common\Cache\Psr6\CacheAdapter;
|
||||
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||
use Doctrine\DBAL\Driver\ResultStatement;
|
||||
use Doctrine\DBAL\Result;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Cache\Exception\InvalidResultCacheDriver;
|
||||
use Doctrine\ORM\Cache\Logging\CacheLogger;
|
||||
use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
use Doctrine\ORM\Cache\TimestampCacheKey;
|
||||
@@ -35,10 +24,13 @@ use Doctrine\ORM\Query\Parameter;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\Persistence\Mapping\MappingException;
|
||||
use LogicException;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Traversable;
|
||||
|
||||
use function array_map;
|
||||
use function array_shift;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function is_array;
|
||||
use function is_numeric;
|
||||
@@ -47,6 +39,7 @@ use function is_scalar;
|
||||
use function iterator_count;
|
||||
use function iterator_to_array;
|
||||
use function ksort;
|
||||
use function method_exists;
|
||||
use function reset;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
@@ -85,6 +78,11 @@ abstract class AbstractQuery
|
||||
*/
|
||||
public const HYDRATE_SIMPLEOBJECT = 5;
|
||||
|
||||
/**
|
||||
* Hydrates scalar column value.
|
||||
*/
|
||||
public const HYDRATE_SCALAR_COLUMN = 6;
|
||||
|
||||
/**
|
||||
* The parameter map of this query.
|
||||
*
|
||||
@@ -96,7 +94,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* The user-specified ResultSetMapping to use.
|
||||
*
|
||||
* @var ResultSetMapping
|
||||
* @var ResultSetMapping|null
|
||||
*/
|
||||
protected $_resultSetMapping;
|
||||
|
||||
@@ -118,6 +116,7 @@ abstract class AbstractQuery
|
||||
* The hydration mode.
|
||||
*
|
||||
* @var string|int
|
||||
* @psalm-var string|AbstractQuery::HYDRATE_*
|
||||
*/
|
||||
protected $_hydrationMode = self::HYDRATE_OBJECT;
|
||||
|
||||
@@ -131,7 +130,7 @@ abstract class AbstractQuery
|
||||
*/
|
||||
protected $_expireResultCache = false;
|
||||
|
||||
/** @var QueryCacheProfile */
|
||||
/** @var QueryCacheProfile|null */
|
||||
protected $_hydrationCacheProfile;
|
||||
|
||||
/**
|
||||
@@ -155,6 +154,7 @@ abstract class AbstractQuery
|
||||
* Second level query cache mode.
|
||||
*
|
||||
* @var int|null
|
||||
* @psalm-var Cache::MODE_*|null
|
||||
*/
|
||||
protected $cacheMode;
|
||||
|
||||
@@ -186,7 +186,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @param bool $cacheable
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setCacheable($cacheable)
|
||||
{
|
||||
@@ -206,7 +206,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* @param string $cacheRegion
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setCacheRegion($cacheRegion)
|
||||
{
|
||||
@@ -246,7 +246,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @param int $lifetime
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setLifetime($lifetime)
|
||||
{
|
||||
@@ -256,7 +256,8 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @return int|null
|
||||
* @psalm-return Cache::MODE_*|null
|
||||
*/
|
||||
public function getCacheMode()
|
||||
{
|
||||
@@ -265,8 +266,9 @@ abstract class AbstractQuery
|
||||
|
||||
/**
|
||||
* @param int $cacheMode
|
||||
* @psalm-param Cache::MODE_* $cacheMode
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setCacheMode($cacheMode)
|
||||
{
|
||||
@@ -347,7 +349,7 @@ abstract class AbstractQuery
|
||||
* @param ArrayCollection|mixed[] $parameters
|
||||
* @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setParameters($parameters)
|
||||
{
|
||||
@@ -371,13 +373,13 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Sets a query parameter.
|
||||
*
|
||||
* @param string|int $key The parameter position or name.
|
||||
* @param mixed $value The parameter value.
|
||||
* @param string|null $type The parameter type. If specified, the given value will be run through
|
||||
* the type conversion of this type. This is usually not needed for
|
||||
* strings and numeric types.
|
||||
* @param string|int $key The parameter position or name.
|
||||
* @param mixed $value The parameter value.
|
||||
* @param string|int|null $type The parameter type. If specified, the given value will be run through
|
||||
* the type conversion of this type. This is usually not needed for
|
||||
* strings and numeric types.
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setParameter($key, $value, $type = null)
|
||||
{
|
||||
@@ -424,15 +426,20 @@ abstract class AbstractQuery
|
||||
return $value->name;
|
||||
}
|
||||
|
||||
if ($value instanceof BackedEnum) {
|
||||
return $value->value;
|
||||
}
|
||||
|
||||
if (! is_object($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
try {
|
||||
$class = ClassUtils::getClass($value);
|
||||
$value = $this->_em->getUnitOfWork()->getSingleIdentifierValue($value);
|
||||
|
||||
if ($value === null) {
|
||||
throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
|
||||
throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($class);
|
||||
}
|
||||
} catch (MappingException | ORMMappingException $e) {
|
||||
/* Silence any mapping exceptions. These can occur if the object in
|
||||
@@ -484,7 +491,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Sets the ResultSetMapping that should be used for hydration.
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setResultSetMapping(Query\ResultSetMapping $rsm)
|
||||
{
|
||||
@@ -497,7 +504,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Gets the ResultSetMapping used for hydration.
|
||||
*
|
||||
* @return ResultSetMapping
|
||||
* @return ResultSetMapping|null
|
||||
*/
|
||||
protected function getResultSetMapping()
|
||||
{
|
||||
@@ -529,7 +536,7 @@ abstract class AbstractQuery
|
||||
* some form of caching with UnitOfWork registration you should use
|
||||
* {@see AbstractQuery::setResultCacheProfile()}.
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*
|
||||
* @example
|
||||
* $lifetime = 100;
|
||||
@@ -539,9 +546,25 @@ abstract class AbstractQuery
|
||||
*/
|
||||
public function setHydrationCacheProfile(?QueryCacheProfile $profile = null)
|
||||
{
|
||||
if ($profile !== null && ! $profile->getResultCacheDriver()) {
|
||||
$resultCacheDriver = $this->_em->getConfiguration()->getHydrationCacheImpl();
|
||||
$profile = $profile->setResultCacheDriver($resultCacheDriver);
|
||||
if ($profile === null) {
|
||||
$this->_hydrationCacheProfile = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// DBAL 2
|
||||
if (! method_exists(QueryCacheProfile::class, 'setResultCache')) {
|
||||
if (! $profile->getResultCacheDriver()) {
|
||||
$defaultHydrationCacheImpl = $this->_em->getConfiguration()->getHydrationCache();
|
||||
if ($defaultHydrationCacheImpl) {
|
||||
$profile = $profile->setResultCacheDriver(DoctrineProvider::wrap($defaultHydrationCacheImpl));
|
||||
}
|
||||
}
|
||||
} elseif (! $profile->getResultCache()) {
|
||||
$defaultHydrationCacheImpl = $this->_em->getConfiguration()->getHydrationCache();
|
||||
if ($defaultHydrationCacheImpl) {
|
||||
$profile = $profile->setResultCache($defaultHydrationCacheImpl);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_hydrationCacheProfile = $profile;
|
||||
@@ -550,7 +573,7 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
/**
|
||||
* @return QueryCacheProfile
|
||||
* @return QueryCacheProfile|null
|
||||
*/
|
||||
public function getHydrationCacheProfile()
|
||||
{
|
||||
@@ -563,13 +586,29 @@ abstract class AbstractQuery
|
||||
* If no result cache driver is set in the QueryCacheProfile, the default
|
||||
* result cache driver is used from the configuration.
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setResultCacheProfile(?QueryCacheProfile $profile = null)
|
||||
{
|
||||
if ($profile !== null && ! $profile->getResultCacheDriver()) {
|
||||
$resultCacheDriver = $this->_em->getConfiguration()->getResultCacheImpl();
|
||||
$profile = $profile->setResultCacheDriver($resultCacheDriver);
|
||||
if ($profile === null) {
|
||||
$this->_queryCacheProfile = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// DBAL 2
|
||||
if (! method_exists(QueryCacheProfile::class, 'setResultCache')) {
|
||||
if (! $profile->getResultCacheDriver()) {
|
||||
$defaultResultCacheDriver = $this->_em->getConfiguration()->getResultCache();
|
||||
if ($defaultResultCacheDriver) {
|
||||
$profile = $profile->setResultCacheDriver(DoctrineProvider::wrap($defaultResultCacheDriver));
|
||||
}
|
||||
}
|
||||
} elseif (! $profile->getResultCache()) {
|
||||
$defaultResultCache = $this->_em->getConfiguration()->getResultCache();
|
||||
if ($defaultResultCache) {
|
||||
$profile = $profile->setResultCache($defaultResultCache);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_queryCacheProfile = $profile;
|
||||
@@ -580,22 +619,53 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Defines a cache driver to be used for caching result sets and implicitly enables caching.
|
||||
*
|
||||
* @deprecated Use {@see setResultCache()} instead.
|
||||
*
|
||||
* @param \Doctrine\Common\Cache\Cache|null $resultCacheDriver Cache driver
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*
|
||||
* @throws ORMException
|
||||
* @throws InvalidResultCacheDriver
|
||||
*/
|
||||
public function setResultCacheDriver($resultCacheDriver = null)
|
||||
{
|
||||
/** @phpstan-ignore-next-line */
|
||||
if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) {
|
||||
throw ORMException::invalidResultCacheDriver();
|
||||
throw InvalidResultCacheDriver::create();
|
||||
}
|
||||
|
||||
return $this->setResultCache($resultCacheDriver ? CacheAdapter::wrap($resultCacheDriver) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a cache driver to be used for caching result sets and implicitly enables caching.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setResultCache(?CacheItemPoolInterface $resultCache = null)
|
||||
{
|
||||
if ($resultCache === null) {
|
||||
if ($this->_queryCacheProfile) {
|
||||
$this->_queryCacheProfile = new QueryCacheProfile($this->_queryCacheProfile->getLifetime(), $this->_queryCacheProfile->getCacheKey());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// DBAL 2
|
||||
if (! method_exists(QueryCacheProfile::class, 'setResultCache')) {
|
||||
$resultCacheDriver = DoctrineProvider::wrap($resultCache);
|
||||
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||
? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
|
||||
: new QueryCacheProfile(0, null, $resultCacheDriver);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||
? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
|
||||
: new QueryCacheProfile(0, null, $resultCacheDriver);
|
||||
? $this->_queryCacheProfile->setResultCache($resultCache)
|
||||
: new QueryCacheProfile(0, null, $resultCache);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -626,7 +696,7 @@ abstract class AbstractQuery
|
||||
* @param int $lifetime How long the cache entry is valid, in seconds.
|
||||
* @param string $resultCacheId ID to use for the cache entry.
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function useResultCache($useCache, $lifetime = null, $resultCacheId = null)
|
||||
{
|
||||
@@ -642,7 +712,7 @@ abstract class AbstractQuery
|
||||
* @param int|null $lifetime How long the cache entry is valid, in seconds.
|
||||
* @param string|null $resultCacheId ID to use for the cache entry.
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function enableResultCache(?int $lifetime = null, ?string $resultCacheId = null): self
|
||||
{
|
||||
@@ -655,7 +725,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Disables caching of the results of this query.
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function disableResultCache(): self
|
||||
{
|
||||
@@ -669,15 +739,33 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @param int|null $lifetime How long the cache entry is valid, in seconds.
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setResultCacheLifetime($lifetime)
|
||||
{
|
||||
$lifetime = $lifetime !== null ? (int) $lifetime : 0;
|
||||
$lifetime = (int) $lifetime;
|
||||
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||
? $this->_queryCacheProfile->setLifetime($lifetime)
|
||||
: new QueryCacheProfile($lifetime, null, $this->_em->getConfiguration()->getResultCacheImpl());
|
||||
if ($this->_queryCacheProfile) {
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setLifetime($lifetime);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->_queryCacheProfile = new QueryCacheProfile($lifetime);
|
||||
|
||||
$cache = $this->_em->getConfiguration()->getResultCache();
|
||||
if (! $cache) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Compatibility for DBAL 2
|
||||
if (! method_exists($this->_queryCacheProfile, 'setResultCache')) {
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setResultCacheDriver(DoctrineProvider::wrap($cache));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setResultCache($cache);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -699,7 +787,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @param bool $expire Whether or not to force resultset cache expiration.
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function expireResultCache($expire = true)
|
||||
{
|
||||
@@ -735,7 +823,7 @@ abstract class AbstractQuery
|
||||
* @param string $assocName
|
||||
* @param int $fetchMode
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setFetchMode($class, $assocName, $fetchMode)
|
||||
{
|
||||
@@ -753,8 +841,9 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @param string|int $hydrationMode Doctrine processing mode to be used during hydration process.
|
||||
* One of the Query::HYDRATE_* constants.
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setHydrationMode($hydrationMode)
|
||||
{
|
||||
@@ -767,6 +856,7 @@ abstract class AbstractQuery
|
||||
* Gets the hydration mode currently used by the query.
|
||||
*
|
||||
* @return string|int
|
||||
* @psalm-return string|AbstractQuery::HYDRATE_*
|
||||
*/
|
||||
public function getHydrationMode()
|
||||
{
|
||||
@@ -779,6 +869,7 @@ abstract class AbstractQuery
|
||||
* Alias for execute(null, $hydrationMode = HYDRATE_OBJECT).
|
||||
*
|
||||
* @param string|int $hydrationMode
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -799,6 +890,18 @@ abstract class AbstractQuery
|
||||
return $this->execute(null, self::HYDRATE_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one-dimensional array of results for the query.
|
||||
*
|
||||
* Alias for execute(null, HYDRATE_SCALAR_COLUMN).
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getSingleColumnResult()
|
||||
{
|
||||
return $this->execute(null, self::HYDRATE_SCALAR_COLUMN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scalar results for the query.
|
||||
*
|
||||
@@ -814,7 +917,8 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Get exactly one result or null.
|
||||
*
|
||||
* @param string|int $hydrationMode
|
||||
* @param string|int|null $hydrationMode
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
@@ -851,7 +955,8 @@ abstract class AbstractQuery
|
||||
* If the result is not unique, a NonUniqueResultException is thrown.
|
||||
* If there is no result, a NoResultException is thrown.
|
||||
*
|
||||
* @param string|int $hydrationMode
|
||||
* @param string|int|null $hydrationMode
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
@@ -886,7 +991,6 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @throws NoResultException If the query returned no result.
|
||||
* @throws NonUniqueResultException If the query result is not unique.
|
||||
* @throws NoResultException If the query returned no result.
|
||||
*/
|
||||
public function getSingleScalarResult()
|
||||
{
|
||||
@@ -899,7 +1003,7 @@ abstract class AbstractQuery
|
||||
* @param string $name The name of the hint.
|
||||
* @param mixed $value The value of the hint.
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setHint($name, $value)
|
||||
{
|
||||
@@ -950,6 +1054,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @param ArrayCollection|mixed[]|null $parameters The query parameters.
|
||||
* @param string|int|null $hydrationMode The hydration mode to use.
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode The hydration mode to use.
|
||||
*
|
||||
* @return IterableResult
|
||||
*/
|
||||
@@ -970,7 +1075,11 @@ abstract class AbstractQuery
|
||||
$this->setParameters($parameters);
|
||||
}
|
||||
|
||||
$rsm = $this->getResultSetMapping();
|
||||
$rsm = $this->getResultSetMapping();
|
||||
if ($rsm === null) {
|
||||
throw new LogicException('Uninitialized result set mapping.');
|
||||
}
|
||||
|
||||
$stmt = $this->_doExecute();
|
||||
|
||||
return $this->_em->newHydrator($this->_hydrationMode)->iterate($stmt, $rsm, $this->_hints);
|
||||
@@ -983,6 +1092,7 @@ abstract class AbstractQuery
|
||||
* @param ArrayCollection|array|mixed[] $parameters The query parameters.
|
||||
* @param string|int|null $hydrationMode The hydration mode to use.
|
||||
* @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*
|
||||
* @return iterable<mixed>
|
||||
*/
|
||||
@@ -1000,6 +1110,9 @@ abstract class AbstractQuery
|
||||
}
|
||||
|
||||
$rsm = $this->getResultSetMapping();
|
||||
if ($rsm === null) {
|
||||
throw new LogicException('Uninitialized result set mapping.');
|
||||
}
|
||||
|
||||
if ($rsm->isMixed && count($rsm->scalarMappings) > 0) {
|
||||
throw QueryException::iterateWithMixedResultNotAllowed();
|
||||
@@ -1016,6 +1129,7 @@ abstract class AbstractQuery
|
||||
* @param ArrayCollection|mixed[]|null $parameters Query parameters.
|
||||
* @param string|int|null $hydrationMode Processing mode to be used during the hydration process.
|
||||
* @psalm-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -1034,6 +1148,7 @@ abstract class AbstractQuery
|
||||
* @param ArrayCollection|mixed[]|null $parameters
|
||||
* @param string|int|null $hydrationMode
|
||||
* @psalm-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -1053,9 +1168,9 @@ abstract class AbstractQuery
|
||||
if ($this->_hydrationCacheProfile !== null) {
|
||||
[$cacheKey, $realCacheKey] = $this->getHydrationCacheId();
|
||||
|
||||
$queryCacheProfile = $this->getHydrationCacheProfile();
|
||||
$cache = $queryCacheProfile->getResultCacheDriver();
|
||||
$result = $cache->fetch($cacheKey);
|
||||
$cache = $this->getHydrationCache();
|
||||
$cacheItem = $cache->getItem($cacheKey);
|
||||
$result = $cacheItem->isHit() ? $cacheItem->get() : [];
|
||||
|
||||
if (isset($result[$realCacheKey])) {
|
||||
return $result[$realCacheKey];
|
||||
@@ -1065,10 +1180,8 @@ abstract class AbstractQuery
|
||||
$result = [];
|
||||
}
|
||||
|
||||
$setCacheEntry = static function ($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile): void {
|
||||
$result[$realCacheKey] = $data;
|
||||
|
||||
$cache->save($cacheKey, $result, $queryCacheProfile->getLifetime());
|
||||
$setCacheEntry = static function ($data) use ($cache, $result, $cacheItem, $realCacheKey): void {
|
||||
$cache->save($cacheItem->set($result + [$realCacheKey => $data]));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1080,7 +1193,11 @@ abstract class AbstractQuery
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
$rsm = $this->getResultSetMapping();
|
||||
$rsm = $this->getResultSetMapping();
|
||||
if ($rsm === null) {
|
||||
throw new LogicException('Uninitialized result set mapping.');
|
||||
}
|
||||
|
||||
$data = $this->_em->newHydrator($this->_hydrationMode)->hydrateAll($stmt, $rsm, $this->_hints);
|
||||
|
||||
$setCacheEntry($data);
|
||||
@@ -1088,18 +1205,41 @@ abstract class AbstractQuery
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function getHydrationCache(): CacheItemPoolInterface
|
||||
{
|
||||
assert($this->_hydrationCacheProfile !== null);
|
||||
|
||||
// Support for DBAL 2
|
||||
if (! method_exists($this->_hydrationCacheProfile, 'getResultCache')) {
|
||||
$cacheDriver = $this->_hydrationCacheProfile->getResultCacheDriver();
|
||||
assert($cacheDriver !== null);
|
||||
|
||||
return CacheAdapter::wrap($cacheDriver);
|
||||
}
|
||||
|
||||
$cache = $this->_hydrationCacheProfile->getResultCache();
|
||||
assert($cache !== null);
|
||||
|
||||
return $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from second level cache or executes the query and put into cache.
|
||||
*
|
||||
* @param ArrayCollection|mixed[]|null $parameters
|
||||
* @param string|int|null $hydrationMode
|
||||
* @psalm-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
|
||||
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function executeUsingQueryCache($parameters = null, $hydrationMode = null)
|
||||
{
|
||||
$rsm = $this->getResultSetMapping();
|
||||
$rsm = $this->getResultSetMapping();
|
||||
if ($rsm === null) {
|
||||
throw new LogicException('Uninitialized result set mapping.');
|
||||
}
|
||||
|
||||
$queryCache = $this->_em->getCache()->getQueryCache($this->cacheRegion);
|
||||
$queryKey = new QueryCacheKey(
|
||||
$this->getHash(),
|
||||
@@ -1134,6 +1274,7 @@ abstract class AbstractQuery
|
||||
|
||||
private function getTimestampKey(): ?TimestampCacheKey
|
||||
{
|
||||
assert($this->_resultSetMapping !== null);
|
||||
$entityName = reset($this->_resultSetMapping->aliasMap);
|
||||
|
||||
if (empty($entityName)) {
|
||||
@@ -1150,7 +1291,8 @@ abstract class AbstractQuery
|
||||
* Will return the configured id if it exists otherwise a hash will be
|
||||
* automatically generated for you.
|
||||
*
|
||||
* @return array<string, string> ($key, $hash)
|
||||
* @return string[] ($key, $hash)
|
||||
* @psalm-return array{string, string} ($key, $hash)
|
||||
*/
|
||||
protected function getHydrationCacheId()
|
||||
{
|
||||
@@ -1166,6 +1308,7 @@ abstract class AbstractQuery
|
||||
$hints['hydrationMode'] = $this->getHydrationMode();
|
||||
|
||||
ksort($hints);
|
||||
assert($queryCacheProfile !== null);
|
||||
|
||||
return $queryCacheProfile->generateCacheKeys($sql, $parameters, $hints);
|
||||
}
|
||||
@@ -1175,15 +1318,17 @@ abstract class AbstractQuery
|
||||
* If this is not explicitly set by the developer then a hash is automatically
|
||||
* generated for you.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string|null $id
|
||||
*
|
||||
* @return static This query instance.
|
||||
* @return $this
|
||||
*/
|
||||
public function setResultCacheId($id)
|
||||
{
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||
? $this->_queryCacheProfile->setCacheKey($id)
|
||||
: new QueryCacheProfile(0, $id, $this->_em->getConfiguration()->getResultCacheImpl());
|
||||
if (! $this->_queryCacheProfile) {
|
||||
return $this->setResultCacheProfile(new QueryCacheProfile(0, $id));
|
||||
}
|
||||
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setCacheKey($id);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -1193,7 +1338,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getResultCacheId()
|
||||
{
|
||||
@@ -1203,9 +1348,9 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Executes the query and returns a the resulting Statement object.
|
||||
*
|
||||
* @return ResultStatement|int The executed database statement that holds
|
||||
* the results, or an integer indicating how
|
||||
* many rows were affected.
|
||||
* @return Result|int The executed database statement that holds
|
||||
* the results, or an integer indicating how
|
||||
* many rows were affected.
|
||||
*/
|
||||
abstract protected function _doExecute();
|
||||
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
@@ -157,6 +141,8 @@ interface Cache
|
||||
* Evicts all cached query results under the given name, or default query cache if the region name is NULL.
|
||||
*
|
||||
* @param string|null $regionName The cache name associated to the queries being cached.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function evictQueryRegion($regionName = null);
|
||||
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -26,22 +10,26 @@ namespace Doctrine\ORM\Cache;
|
||||
class AssociationCacheEntry implements CacheEntry
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* The entity identifier
|
||||
*
|
||||
* @var array<string, mixed> The entity identifier
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $identifier;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* The entity class name
|
||||
*
|
||||
* @var string The entity class name
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
*/
|
||||
public $class;
|
||||
|
||||
/**
|
||||
* @param string $class The entity class.
|
||||
* @param array<string, mixed> $identifier The entity identifier.
|
||||
* @psalm-param class-string $class
|
||||
*/
|
||||
public function __construct($class, array $identifier)
|
||||
{
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
|
||||
@@ -1,26 +1,10 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\ORM\ORMException;
|
||||
use Doctrine\ORM\Exception\ORMException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
@@ -41,6 +25,8 @@ class CacheException extends ORMException
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method is not used anymore.
|
||||
*
|
||||
* @param string $entityName
|
||||
*
|
||||
* @return CacheException
|
||||
@@ -61,6 +47,8 @@ class CacheException extends ORMException
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method is not used anymore.
|
||||
*
|
||||
* @param string $entityName
|
||||
* @param string $field
|
||||
*
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -47,9 +31,7 @@ interface CacheFactory
|
||||
/**
|
||||
* Build a collection persister for the given relation mapping.
|
||||
*
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param CollectionPersister $persister The collection persister that will be cached.
|
||||
* @param mixed[] $mapping The association mapping.
|
||||
* @param mixed[] $mapping The association mapping.
|
||||
*
|
||||
* @return CachedCollectionPersister
|
||||
*/
|
||||
@@ -58,8 +40,7 @@ interface CacheFactory
|
||||
/**
|
||||
* Build a query cache based on the given region name
|
||||
*
|
||||
* @param EntityManagerInterface $em The Entity manager.
|
||||
* @param string $regionName The region name.
|
||||
* @param string|null $regionName The region name.
|
||||
*
|
||||
* @return QueryCache The built query cache.
|
||||
*/
|
||||
@@ -68,9 +49,6 @@ interface CacheFactory
|
||||
/**
|
||||
* Build an entity hydrator
|
||||
*
|
||||
* @param EntityManagerInterface $em The Entity manager.
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
*
|
||||
* @return EntityHydrator The built entity hydrator.
|
||||
*/
|
||||
public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata);
|
||||
@@ -78,8 +56,7 @@ interface CacheFactory
|
||||
/**
|
||||
* Build a collection hydrator
|
||||
*
|
||||
* @param EntityManagerInterface $em The Entity manager.
|
||||
* @param mixed[] $mapping The association mapping.
|
||||
* @param mixed[] $mapping The association mapping.
|
||||
*
|
||||
* @return CollectionHydrator The built collection hydrator.
|
||||
*/
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -27,9 +11,10 @@ namespace Doctrine\ORM\Cache;
|
||||
abstract class CacheKey
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* Unique identifier
|
||||
*
|
||||
* @var string Unique identifier
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
*/
|
||||
public $hash;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -26,9 +10,10 @@ namespace Doctrine\ORM\Cache;
|
||||
class CollectionCacheEntry implements CacheEntry
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* The list of entity identifiers hold by the collection
|
||||
*
|
||||
* @var CacheKey[] The list of entity identifiers hold by the collection
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var CacheKey[]
|
||||
*/
|
||||
public $identifiers;
|
||||
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -31,23 +15,27 @@ use function strtolower;
|
||||
class CollectionCacheKey extends CacheKey
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* The owner entity identifier
|
||||
*
|
||||
* @var array<string, mixed> The owner entity identifier
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $ownerIdentifier;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* The owner entity class
|
||||
*
|
||||
* @var string The owner entity class
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
*/
|
||||
public $entityClass;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* The association name
|
||||
*
|
||||
* @var string The association name
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
*/
|
||||
public $association;
|
||||
|
||||
@@ -55,6 +43,7 @@ class CollectionCacheKey extends CacheKey
|
||||
* @param string $entityClass The entity class.
|
||||
* @param string $association The field name that represents the association.
|
||||
* @param array<string, mixed> $ownerIdentifier The identifier of the owning entity.
|
||||
* @psalm-param class-string $entityClass
|
||||
*/
|
||||
public function __construct($entityClass, $association, array $ownerIdentifier)
|
||||
{
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -30,8 +14,6 @@ use Doctrine\ORM\PersistentCollection;
|
||||
interface CollectionHydrator
|
||||
{
|
||||
/**
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param CollectionCacheKey $key The cached collection key.
|
||||
* @param array|mixed[]|Collection $collection The collection.
|
||||
*
|
||||
* @return CollectionCacheEntry
|
||||
@@ -39,12 +21,7 @@ interface CollectionHydrator
|
||||
public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, $collection);
|
||||
|
||||
/**
|
||||
* @param ClassMetadata $metadata The owning entity metadata.
|
||||
* @param CollectionCacheKey $key The cached collection key.
|
||||
* @param CollectionCacheEntry $entry The cached collection entry.
|
||||
* @param PersistentCollection $collection The collection to load the cache into.
|
||||
*
|
||||
* @return mixed[]
|
||||
* @return mixed[]|null
|
||||
*/
|
||||
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -34,7 +18,7 @@ interface ConcurrentRegion extends Region
|
||||
*
|
||||
* @param CacheKey $key The key of the item to lock.
|
||||
*
|
||||
* @return Lock A lock instance or NULL if the lock already exists.
|
||||
* @return Lock|null A lock instance or NULL if the lock already exists.
|
||||
*
|
||||
* @throws LockException Indicates a problem accessing the region.
|
||||
*/
|
||||
@@ -46,7 +30,7 @@ interface ConcurrentRegion extends Region
|
||||
* @param CacheKey $key The key of the item to unlock.
|
||||
* @param Lock $lock The lock previously obtained from {@link readLock}
|
||||
*
|
||||
* @return void
|
||||
* @return bool
|
||||
*
|
||||
* @throws LockException Indicates a problem accessing the region.
|
||||
*/
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -45,7 +29,10 @@ class DefaultCache implements Cache
|
||||
/** @var CacheFactory */
|
||||
private $cacheFactory;
|
||||
|
||||
/** @var QueryCache[] */
|
||||
/**
|
||||
* @var QueryCache[]
|
||||
* @psalm-var array<string, QueryCache>
|
||||
*/
|
||||
private $queryCaches = [];
|
||||
|
||||
/** @var QueryCache|null */
|
||||
@@ -275,10 +262,9 @@ class DefaultCache implements Cache
|
||||
return $this->queryCaches[$regionName];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*/
|
||||
/**
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*/
|
||||
private function buildEntityCacheKey(ClassMetadata $metadata, $identifier): EntityCacheKey
|
||||
{
|
||||
if (! is_array($identifier)) {
|
||||
@@ -289,9 +275,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param string $association The field name that represents the association.
|
||||
* @param mixed $ownerIdentifier The identifier of the owning entity.
|
||||
* @param mixed $ownerIdentifier The identifier of the owning entity.
|
||||
*/
|
||||
private function buildCollectionCacheKey(
|
||||
ClassMetadata $metadata,
|
||||
@@ -306,18 +290,20 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function toIdentifierArray(ClassMetadata $metadata, $identifier): array
|
||||
{
|
||||
if (is_object($identifier) && $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($identifier))) {
|
||||
$identifier = $this->uow->getSingleIdentifierValue($identifier);
|
||||
if (is_object($identifier)) {
|
||||
$class = ClassUtils::getClass($identifier);
|
||||
if ($this->em->getMetadataFactory()->hasMetadataFor($class)) {
|
||||
$identifier = $this->uow->getSingleIdentifierValue($identifier);
|
||||
|
||||
if ($identifier === null) {
|
||||
throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
|
||||
if ($identifier === null) {
|
||||
throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,12 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\Common\Cache\Cache as CacheAdapter;
|
||||
use Doctrine\Common\Cache\CacheProvider;
|
||||
use Doctrine\Common\Cache\MultiGetCache;
|
||||
use Doctrine\Common\Cache\Cache as LegacyCache;
|
||||
use Doctrine\Common\Cache\Psr6\CacheAdapter;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Cache;
|
||||
use Doctrine\ORM\Cache\Persister\Collection\NonStrictReadWriteCachedCollectionPersister;
|
||||
use Doctrine\ORM\Cache\Persister\Collection\ReadOnlyCachedCollectionPersister;
|
||||
@@ -30,7 +14,6 @@ use Doctrine\ORM\Cache\Persister\Collection\ReadWriteCachedCollectionPersister;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\NonStrictReadWriteCachedEntityPersister;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\ReadOnlyCachedEntityPersister;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\ReadWriteCachedEntityPersister;
|
||||
use Doctrine\ORM\Cache\Region\DefaultMultiGetRegion;
|
||||
use Doctrine\ORM\Cache\Region\DefaultRegion;
|
||||
use Doctrine\ORM\Cache\Region\FileLockRegion;
|
||||
use Doctrine\ORM\Cache\Region\UpdateTimestampCache;
|
||||
@@ -40,15 +23,19 @@ use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use TypeError;
|
||||
|
||||
use function assert;
|
||||
use function get_debug_type;
|
||||
use function sprintf;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
class DefaultCacheFactory implements CacheFactory
|
||||
{
|
||||
/** @var CacheAdapter */
|
||||
private $cache;
|
||||
/** @var CacheItemPoolInterface */
|
||||
private $cacheItemPool;
|
||||
|
||||
/** @var RegionsConfiguration */
|
||||
private $regionsConfig;
|
||||
@@ -62,9 +49,33 @@ class DefaultCacheFactory implements CacheFactory
|
||||
/** @var string|null */
|
||||
private $fileLockRegionDirectory;
|
||||
|
||||
public function __construct(RegionsConfiguration $cacheConfig, CacheAdapter $cache)
|
||||
/**
|
||||
* @param CacheItemPoolInterface $cacheItemPool
|
||||
*/
|
||||
public function __construct(RegionsConfiguration $cacheConfig, $cacheItemPool)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
if ($cacheItemPool instanceof LegacyCache) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/9322',
|
||||
'Passing an instance of %s to %s is deprecated, pass a %s instead.',
|
||||
get_debug_type($cacheItemPool),
|
||||
__METHOD__,
|
||||
CacheItemPoolInterface::class
|
||||
);
|
||||
|
||||
$this->cacheItemPool = CacheAdapter::wrap($cacheItemPool);
|
||||
} elseif (! $cacheItemPool instanceof CacheItemPoolInterface) {
|
||||
throw new TypeError(sprintf(
|
||||
'%s: Parameter #2 is expected to be an instance of %s, got %s.',
|
||||
__METHOD__,
|
||||
CacheItemPoolInterface::class,
|
||||
get_debug_type($cacheItemPool)
|
||||
));
|
||||
} else {
|
||||
$this->cacheItemPool = $cacheItemPool;
|
||||
}
|
||||
|
||||
$this->regionsConfig = $cacheConfig;
|
||||
}
|
||||
|
||||
@@ -107,6 +118,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
*/
|
||||
public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata)
|
||||
{
|
||||
assert($metadata->cache !== null);
|
||||
$region = $this->getRegion($metadata->cache);
|
||||
$usage = $metadata->cache['usage'];
|
||||
|
||||
@@ -197,13 +209,9 @@ class DefaultCacheFactory implements CacheFactory
|
||||
return $this->regions[$cache['region']];
|
||||
}
|
||||
|
||||
$name = $cache['region'];
|
||||
$cacheAdapter = $this->createRegionCache($name);
|
||||
$lifetime = $this->regionsConfig->getLifetime($cache['region']);
|
||||
|
||||
$region = $cacheAdapter instanceof MultiGetCache
|
||||
? new DefaultMultiGetRegion($name, $cacheAdapter, $lifetime)
|
||||
: new DefaultRegion($name, $cacheAdapter, $lifetime);
|
||||
$name = $cache['region'];
|
||||
$lifetime = $this->regionsConfig->getLifetime($cache['region']);
|
||||
$region = new DefaultRegion($name, $this->cacheItemPool, $lifetime);
|
||||
|
||||
if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) {
|
||||
if (
|
||||
@@ -223,25 +231,6 @@ class DefaultCacheFactory implements CacheFactory
|
||||
return $this->regions[$cache['region']] = $region;
|
||||
}
|
||||
|
||||
private function createRegionCache(string $name): CacheAdapter
|
||||
{
|
||||
$cacheAdapter = clone $this->cache;
|
||||
|
||||
if (! $cacheAdapter instanceof CacheProvider) {
|
||||
return $cacheAdapter;
|
||||
}
|
||||
|
||||
$namespace = $cacheAdapter->getNamespace();
|
||||
|
||||
if ($namespace !== '') {
|
||||
$namespace .= ':';
|
||||
}
|
||||
|
||||
$cacheAdapter->setNamespace($namespace . $name);
|
||||
|
||||
return $cacheAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -251,7 +240,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
$name = Cache::DEFAULT_TIMESTAMP_REGION_NAME;
|
||||
$lifetime = $this->regionsConfig->getLifetime($name);
|
||||
|
||||
$this->timestampRegion = new UpdateTimestampCache($name, clone $this->cache, $lifetime);
|
||||
$this->timestampRegion = new UpdateTimestampCache($name, $this->cacheItemPool, $lifetime);
|
||||
}
|
||||
|
||||
return $this->timestampRegion;
|
||||
@@ -260,8 +249,8 @@ class DefaultCacheFactory implements CacheFactory
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createCache(EntityManagerInterface $em)
|
||||
public function createCache(EntityManagerInterface $entityManager)
|
||||
{
|
||||
return new DefaultCache($em);
|
||||
return new DefaultCache($entityManager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -27,7 +11,6 @@ use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function array_walk;
|
||||
use function assert;
|
||||
|
||||
/**
|
||||
@@ -86,12 +69,16 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
}
|
||||
|
||||
foreach ($entityEntries as $index => $entityEntry) {
|
||||
$list[$index] = $this->uow->createEntity($entityEntry->class, $entityEntry->resolveAssociationEntries($this->em), self::$hints);
|
||||
}
|
||||
$entity = $this->uow->createEntity(
|
||||
$entityEntry->class,
|
||||
$entityEntry->resolveAssociationEntries($this->em),
|
||||
self::$hints
|
||||
);
|
||||
|
||||
array_walk($list, static function ($entity, $index) use ($collection) {
|
||||
$collection->hydrateSet($index, $entity);
|
||||
});
|
||||
|
||||
$list[$index] = $entity;
|
||||
}
|
||||
|
||||
$this->uow->hydrationComplete();
|
||||
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -71,8 +55,16 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
$data = $this->uow->getOriginalEntityData($entity);
|
||||
$data = array_merge($data, $metadata->getIdentifierValues($entity)); // why update has no identifier values ?
|
||||
|
||||
if ($metadata->isVersioned) {
|
||||
$data[$metadata->versionField] = $metadata->getFieldValue($entity, $metadata->versionField);
|
||||
if ($metadata->requiresFetchAfterChange) {
|
||||
if ($metadata->isVersioned) {
|
||||
$data[$metadata->versionField] = $metadata->getFieldValue($entity, $metadata->versionField);
|
||||
}
|
||||
|
||||
foreach ($metadata->fieldMappings as $name => $fieldMapping) {
|
||||
if (isset($fieldMapping['generated'])) {
|
||||
$data[$name] = $metadata->getFieldValue($entity, $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($metadata->associationMappings as $name => $assoc) {
|
||||
|
||||
@@ -1,28 +1,14 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Proxy\Proxy;
|
||||
use Doctrine\ORM\Cache;
|
||||
use Doctrine\ORM\Cache\Exception\FeatureNotImplemented;
|
||||
use Doctrine\ORM\Cache\Exception\NonCacheableEntity;
|
||||
use Doctrine\ORM\Cache\Logging\CacheLogger;
|
||||
use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@@ -32,7 +18,6 @@ use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_map;
|
||||
use function array_shift;
|
||||
use function array_unshift;
|
||||
@@ -47,7 +32,7 @@ use function reset;
|
||||
*/
|
||||
class DefaultQueryCache implements QueryCache
|
||||
{
|
||||
/** @var EntityManagerInterface */
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
/** @var UnitOfWork */
|
||||
@@ -59,7 +44,7 @@ class DefaultQueryCache implements QueryCache
|
||||
/** @var QueryCacheValidator */
|
||||
private $validator;
|
||||
|
||||
/** @var CacheLogger */
|
||||
/** @var CacheLogger|null */
|
||||
protected $cacheLogger;
|
||||
|
||||
/** @var array<string,mixed> */
|
||||
@@ -186,7 +171,7 @@ class DefaultQueryCache implements QueryCache
|
||||
$assocEntries = $assocRegion->getMultiple($assocKeys);
|
||||
|
||||
foreach ($assoc['list'] as $assocIndex => $assocId) {
|
||||
$assocEntry = is_array($assocEntries) && array_key_exists($assocIndex, $assocEntries) ? $assocEntries[$assocIndex] : null;
|
||||
$assocEntry = is_array($assocEntries) ? ($assocEntries[$assocIndex] ?? null) : null;
|
||||
|
||||
if ($assocEntry === null) {
|
||||
if ($this->cacheLogger !== null) {
|
||||
@@ -245,19 +230,19 @@ class DefaultQueryCache implements QueryCache
|
||||
public function put(QueryCacheKey $key, ResultSetMapping $rsm, $result, array $hints = [])
|
||||
{
|
||||
if ($rsm->scalarMappings) {
|
||||
throw new CacheException('Second level cache does not support scalar results.');
|
||||
throw FeatureNotImplemented::scalarResults();
|
||||
}
|
||||
|
||||
if (count($rsm->entityMappings) > 1) {
|
||||
throw new CacheException('Second level cache does not support multiple root entities.');
|
||||
throw FeatureNotImplemented::multipleRootEntities();
|
||||
}
|
||||
|
||||
if (! $rsm->isSelect) {
|
||||
throw new CacheException('Second-level cache query supports only select statements.');
|
||||
throw FeatureNotImplemented::nonSelectStatements();
|
||||
}
|
||||
|
||||
if (($hints[Query\SqlWalker::HINT_PARTIAL] ?? false) === true || ($hints[Query::HINT_FORCE_PARTIAL_LOAD] ?? false) === true) {
|
||||
throw new CacheException('Second level cache does not support partial entities.');
|
||||
throw FeatureNotImplemented::partialEntities();
|
||||
}
|
||||
|
||||
if (! ($key->cacheMode & Cache::MODE_PUT)) {
|
||||
@@ -270,7 +255,7 @@ class DefaultQueryCache implements QueryCache
|
||||
$persister = $this->uow->getEntityPersister($entityName);
|
||||
|
||||
if (! $persister instanceof CachedEntityPersister) {
|
||||
throw CacheException::nonCacheableEntity($entityName);
|
||||
throw NonCacheableEntity::fromEntity($entityName);
|
||||
}
|
||||
|
||||
$region = $persister->getCacheRegion();
|
||||
@@ -399,7 +384,8 @@ class DefaultQueryCache implements QueryCache
|
||||
/**
|
||||
* @param object $entity
|
||||
*
|
||||
* @return array<object>|object
|
||||
* @return mixed[]|object|null
|
||||
* @psalm-return list<mixed>|object|null
|
||||
*/
|
||||
private function getAssociationValue(
|
||||
ResultSetMapping $rsm,
|
||||
@@ -426,10 +412,11 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @param array<mixed> $path
|
||||
* @param mixed $value
|
||||
* @psalm-param array<array-key, array{field: string, class: string}> $path
|
||||
*
|
||||
* @return mixed
|
||||
* @return mixed[]|object|null
|
||||
* @psalm-return list<mixed>|object|null
|
||||
*/
|
||||
private function getAssociationPathValue($value, array $path)
|
||||
{
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -30,16 +14,18 @@ use function array_map;
|
||||
class EntityCacheEntry implements CacheEntry
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* The entity map data
|
||||
*
|
||||
* @var array<string,mixed> The entity map data
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var array<string,mixed>
|
||||
*/
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* The entity class name
|
||||
*
|
||||
* @var string The entity class name
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
*/
|
||||
public $class;
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -31,22 +15,26 @@ use function strtolower;
|
||||
class EntityCacheKey extends CacheKey
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* The entity identifier
|
||||
*
|
||||
* @var array<string, mixed> The entity identifier
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $identifier;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* The entity class name
|
||||
*
|
||||
* @var string The entity class name
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
*/
|
||||
public $entityClass;
|
||||
|
||||
/**
|
||||
* @param string $entityClass The entity class name. In a inheritance hierarchy it should always be the root entity class.
|
||||
* @param array<string, mixed> $identifier The entity identifier
|
||||
* @psalm-param class-string $entityClass
|
||||
*/
|
||||
public function __construct($entityClass, array $identifier)
|
||||
{
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -40,7 +24,9 @@ interface EntityHydrator
|
||||
* @param ClassMetadata $metadata The entity metadata.
|
||||
* @param EntityCacheKey $key The entity cache key.
|
||||
* @param EntityCacheEntry $entry The entity cache entry.
|
||||
* @param object $entity The entity to load the cache into. If not specified, a new entity is created.
|
||||
* @param object|null $entity The entity to load the cache into. If not specified, a new entity is created.
|
||||
*
|
||||
* @return object|null
|
||||
*/
|
||||
public function loadCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, EntityCacheEntry $entry, $entity = null);
|
||||
}
|
||||
|
||||
14
lib/Doctrine/ORM/Cache/Exception/CacheException.php
Normal file
14
lib/Doctrine/ORM/Cache/Exception/CacheException.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
use Doctrine\ORM\Cache\CacheException as BaseCacheException;
|
||||
|
||||
/**
|
||||
* Exception for cache.
|
||||
*/
|
||||
class CacheException extends BaseCacheException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
class CannotUpdateReadOnlyCollection extends CacheException
|
||||
{
|
||||
public static function fromEntityAndField(string $sourceEntity, string $fieldName): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Cannot update a readonly collection "%s#%s"',
|
||||
$sourceEntity,
|
||||
$fieldName
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
class CannotUpdateReadOnlyEntity extends CacheException
|
||||
{
|
||||
public static function fromEntity(string $entityName): self
|
||||
{
|
||||
return new self(sprintf('Cannot update a readonly entity "%s"', $entityName));
|
||||
}
|
||||
}
|
||||
28
lib/Doctrine/ORM/Cache/Exception/FeatureNotImplemented.php
Normal file
28
lib/Doctrine/ORM/Cache/Exception/FeatureNotImplemented.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
class FeatureNotImplemented extends CacheException
|
||||
{
|
||||
public static function scalarResults(): self
|
||||
{
|
||||
return new self('Second level cache does not support scalar results.');
|
||||
}
|
||||
|
||||
public static function multipleRootEntities(): self
|
||||
{
|
||||
return new self('Second level cache does not support multiple root entities.');
|
||||
}
|
||||
|
||||
public static function nonSelectStatements(): self
|
||||
{
|
||||
return new self('Second-level cache query supports only select statements.');
|
||||
}
|
||||
|
||||
public static function partialEntities(): self
|
||||
{
|
||||
return new self('Second level cache does not support partial entities.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
final class InvalidResultCacheDriver extends CacheException
|
||||
{
|
||||
public static function create(): self
|
||||
{
|
||||
return new self(
|
||||
'Invalid result cache driver; it must implement Doctrine\\Common\\Cache\\Cache.'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
final class MetadataCacheNotConfigured extends CacheException
|
||||
{
|
||||
public static function create(): self
|
||||
{
|
||||
return new self('Class Metadata Cache is not configured.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
|
||||
use function get_debug_type;
|
||||
|
||||
final class MetadataCacheUsesNonPersistentCache extends CacheException
|
||||
{
|
||||
public static function fromDriver(Cache $cache): self
|
||||
{
|
||||
return new self(
|
||||
'Metadata Cache uses a non-persistent cache driver, ' . get_debug_type($cache) . '.'
|
||||
);
|
||||
}
|
||||
}
|
||||
18
lib/Doctrine/ORM/Cache/Exception/NonCacheableEntity.php
Normal file
18
lib/Doctrine/ORM/Cache/Exception/NonCacheableEntity.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
class NonCacheableEntity extends CacheException
|
||||
{
|
||||
public static function fromEntity(string $entityName): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Entity "%s" not configured as part of the second-level cache.',
|
||||
$entityName
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
class NonCacheableEntityAssociation extends CacheException
|
||||
{
|
||||
public static function fromEntityAndField(string $entityName, string $field): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Entity association field "%s#%s" not configured as part of the second-level cache.',
|
||||
$entityName,
|
||||
$field
|
||||
));
|
||||
}
|
||||
}
|
||||
13
lib/Doctrine/ORM/Cache/Exception/QueryCacheNotConfigured.php
Normal file
13
lib/Doctrine/ORM/Cache/Exception/QueryCacheNotConfigured.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
final class QueryCacheNotConfigured extends CacheException
|
||||
{
|
||||
public static function create(): self
|
||||
{
|
||||
return new self('Query Cache is not configured.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
|
||||
use function get_debug_type;
|
||||
|
||||
final class QueryCacheUsesNonPersistentCache extends CacheException
|
||||
{
|
||||
public static function fromDriver(Cache $cache): self
|
||||
{
|
||||
return new self(
|
||||
'Query Cache uses a non-persistent cache driver, ' . get_debug_type($cache) . '.'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,12 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use function time;
|
||||
use function uniqid;
|
||||
|
||||
/**
|
||||
* Cache Lock
|
||||
*/
|
||||
class Lock
|
||||
{
|
||||
/** @var string */
|
||||
@@ -34,14 +15,10 @@ class Lock
|
||||
/** @var int */
|
||||
public $time;
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @param int $time
|
||||
*/
|
||||
public function __construct($value, $time = null)
|
||||
public function __construct(string $value, ?int $time = null)
|
||||
{
|
||||
$this->value = $value;
|
||||
$this->time = $time ? : time();
|
||||
$this->time = $time ?: time();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,6 +26,6 @@ class Lock
|
||||
*/
|
||||
public static function createLockRead()
|
||||
{
|
||||
return new self(uniqid(time(), true));
|
||||
return new self(uniqid((string) time(), true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,11 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
use Doctrine\ORM\Cache\Exception\CacheException;
|
||||
|
||||
/**
|
||||
* Lock exception for cache.
|
||||
*/
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Logging;
|
||||
|
||||
@@ -34,6 +18,8 @@ interface CacheLogger
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param EntityCacheKey $key The cache key of the entity.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function entityCachePut($regionName, EntityCacheKey $key);
|
||||
|
||||
@@ -42,6 +28,8 @@ interface CacheLogger
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param EntityCacheKey $key The cache key of the entity.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function entityCacheHit($regionName, EntityCacheKey $key);
|
||||
|
||||
@@ -50,15 +38,19 @@ interface CacheLogger
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param EntityCacheKey $key The cache key of the entity.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function entityCacheMiss($regionName, EntityCacheKey $key);
|
||||
|
||||
/**
|
||||
* Log an entity put into second level cache.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param CollectionCacheKey $key The cache key of the collection.
|
||||
*/
|
||||
/**
|
||||
* Log an entity put into second level cache.
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param CollectionCacheKey $key The cache key of the collection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function collectionCachePut($regionName, CollectionCacheKey $key);
|
||||
|
||||
/**
|
||||
@@ -66,6 +58,8 @@ interface CacheLogger
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param CollectionCacheKey $key The cache key of the collection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function collectionCacheHit($regionName, CollectionCacheKey $key);
|
||||
|
||||
@@ -74,6 +68,8 @@ interface CacheLogger
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param CollectionCacheKey $key The cache key of the collection.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function collectionCacheMiss($regionName, CollectionCacheKey $key);
|
||||
|
||||
@@ -82,6 +78,8 @@ interface CacheLogger
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param QueryCacheKey $key The cache key of the query.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function queryCachePut($regionName, QueryCacheKey $key);
|
||||
|
||||
@@ -90,6 +88,8 @@ interface CacheLogger
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param QueryCacheKey $key The cache key of the query.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function queryCacheHit($regionName, QueryCacheKey $key);
|
||||
|
||||
@@ -98,6 +98,8 @@ interface CacheLogger
|
||||
*
|
||||
* @param string $regionName The name of the cache region.
|
||||
* @param QueryCacheKey $key The cache key of the query.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function queryCacheMiss($regionName, QueryCacheKey $key);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Logging;
|
||||
|
||||
@@ -24,12 +8,9 @@ use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
use Doctrine\ORM\Cache\QueryCacheKey;
|
||||
|
||||
/**
|
||||
* Cache logger chain
|
||||
*/
|
||||
class CacheLoggerChain implements CacheLogger
|
||||
{
|
||||
/** @var array<CacheLogger> */
|
||||
/** @var array<string, CacheLogger> */
|
||||
private $loggers = [];
|
||||
|
||||
/**
|
||||
@@ -53,7 +34,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<CacheLogger>
|
||||
* @return array<string, CacheLogger>
|
||||
*/
|
||||
public function getLoggers()
|
||||
{
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Logging;
|
||||
|
||||
@@ -31,13 +15,13 @@ use function array_sum;
|
||||
*/
|
||||
class StatisticsCacheLogger implements CacheLogger
|
||||
{
|
||||
/** @var int[] */
|
||||
/** @var array<string, int> */
|
||||
private $cacheMissCountMap = [];
|
||||
|
||||
/** @var int[] */
|
||||
/** @var array<string, int> */
|
||||
private $cacheHitCountMap = [];
|
||||
|
||||
/** @var int[] */
|
||||
/** @var array<string, int> */
|
||||
private $cachePutCountMap = [];
|
||||
|
||||
/**
|
||||
@@ -45,9 +29,8 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function collectionCacheMiss($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
$this->cacheMissCountMap[$regionName] = isset($this->cacheMissCountMap[$regionName])
|
||||
? $this->cacheMissCountMap[$regionName] + 1
|
||||
: 1;
|
||||
$this->cacheMissCountMap[$regionName]
|
||||
= ($this->cacheMissCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,9 +38,8 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function collectionCacheHit($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
$this->cacheHitCountMap[$regionName] = isset($this->cacheHitCountMap[$regionName])
|
||||
? $this->cacheHitCountMap[$regionName] + 1
|
||||
: 1;
|
||||
$this->cacheHitCountMap[$regionName]
|
||||
= ($this->cacheHitCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,9 +47,8 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function collectionCachePut($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
$this->cachePutCountMap[$regionName] = isset($this->cachePutCountMap[$regionName])
|
||||
? $this->cachePutCountMap[$regionName] + 1
|
||||
: 1;
|
||||
$this->cachePutCountMap[$regionName]
|
||||
= ($this->cachePutCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,9 +56,8 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function entityCacheMiss($regionName, EntityCacheKey $key)
|
||||
{
|
||||
$this->cacheMissCountMap[$regionName] = isset($this->cacheMissCountMap[$regionName])
|
||||
? $this->cacheMissCountMap[$regionName] + 1
|
||||
: 1;
|
||||
$this->cacheMissCountMap[$regionName]
|
||||
= ($this->cacheMissCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,9 +65,8 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function entityCacheHit($regionName, EntityCacheKey $key)
|
||||
{
|
||||
$this->cacheHitCountMap[$regionName] = isset($this->cacheHitCountMap[$regionName])
|
||||
? $this->cacheHitCountMap[$regionName] + 1
|
||||
: 1;
|
||||
$this->cacheHitCountMap[$regionName]
|
||||
= ($this->cacheHitCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,9 +74,8 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function entityCachePut($regionName, EntityCacheKey $key)
|
||||
{
|
||||
$this->cachePutCountMap[$regionName] = isset($this->cachePutCountMap[$regionName])
|
||||
? $this->cachePutCountMap[$regionName] + 1
|
||||
: 1;
|
||||
$this->cachePutCountMap[$regionName]
|
||||
= ($this->cachePutCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,9 +83,8 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function queryCacheHit($regionName, QueryCacheKey $key)
|
||||
{
|
||||
$this->cacheHitCountMap[$regionName] = isset($this->cacheHitCountMap[$regionName])
|
||||
? $this->cacheHitCountMap[$regionName] + 1
|
||||
: 1;
|
||||
$this->cacheHitCountMap[$regionName]
|
||||
= ($this->cacheHitCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,9 +92,8 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function queryCacheMiss($regionName, QueryCacheKey $key)
|
||||
{
|
||||
$this->cacheMissCountMap[$regionName] = isset($this->cacheMissCountMap[$regionName])
|
||||
? $this->cacheMissCountMap[$regionName] + 1
|
||||
: 1;
|
||||
$this->cacheMissCountMap[$regionName]
|
||||
= ($this->cacheMissCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,9 +101,8 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
*/
|
||||
public function queryCachePut($regionName, QueryCacheKey $key)
|
||||
{
|
||||
$this->cachePutCountMap[$regionName] = isset($this->cachePutCountMap[$regionName])
|
||||
? $this->cachePutCountMap[$regionName] + 1
|
||||
: 1;
|
||||
$this->cachePutCountMap[$regionName]
|
||||
= ($this->cachePutCountMap[$regionName] ?? 0) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -24,6 +8,8 @@ namespace Doctrine\ORM\Cache;
|
||||
* Defines a region that supports multi-get reading.
|
||||
*
|
||||
* With one method call we can get multiple items.
|
||||
*
|
||||
* @deprecated Implement {@see Region} instead.
|
||||
*/
|
||||
interface MultiGetRegion
|
||||
{
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister;
|
||||
|
||||
@@ -29,11 +13,15 @@ interface CachedPersister
|
||||
{
|
||||
/**
|
||||
* Perform whatever processing is encapsulated here after completion of the transaction.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function afterTransactionComplete();
|
||||
|
||||
/**
|
||||
* Perform whatever processing is encapsulated here after completion of the rolled-back.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function afterTransactionRolledBack();
|
||||
|
||||
|
||||
@@ -1,27 +1,13 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\CollectionHydrator;
|
||||
use Doctrine\ORM\Cache\EntityCacheKey;
|
||||
@@ -38,11 +24,10 @@ use Doctrine\ORM\UnitOfWork;
|
||||
use function array_values;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function is_array;
|
||||
|
||||
abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
{
|
||||
/** @var UnitOfWork */
|
||||
/** @var UnitOfWork */
|
||||
protected $uow;
|
||||
|
||||
/** @var ClassMetadataFactory */
|
||||
@@ -60,7 +45,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
/** @var mixed[] */
|
||||
protected $association;
|
||||
|
||||
/** @var mixed[] */
|
||||
/** @var mixed[] */
|
||||
protected $queuedCache = [];
|
||||
|
||||
/** @var Region */
|
||||
@@ -124,7 +109,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object[]|null
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -151,7 +136,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
// Only preserve ordering if association configured it
|
||||
if (! (isset($associationMapping['indexBy']) && $associationMapping['indexBy'])) {
|
||||
// Elements may be an array or a Collection
|
||||
$elements = array_values(is_array($elements) ? $elements : $elements->getValues());
|
||||
$elements = array_values($elements instanceof Collection ? $elements->getValues() : $elements);
|
||||
}
|
||||
|
||||
$entry = $this->hydrator->buildCacheEntry($this->targetEntity, $key, $elements);
|
||||
@@ -240,10 +225,18 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
/**
|
||||
* Clears cache entries related to the current collection
|
||||
*
|
||||
* @deprecated This method is not used anymore.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function evictCollectionCache(PersistentCollection $collection)
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/9512',
|
||||
'The method %s() is deprecated and will be removed without replacement.'
|
||||
);
|
||||
|
||||
$key = new CollectionCacheKey(
|
||||
$this->sourceEntity->rootEntityName,
|
||||
$this->association['fieldName'],
|
||||
@@ -258,13 +251,22 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method is not used anymore.
|
||||
*
|
||||
* @param string $targetEntity
|
||||
* @param object $element
|
||||
* @psalm-param class-string $targetEntity
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function evictElementCache($targetEntity, $element)
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/9512',
|
||||
'The method %s() is deprecated and will be removed without replacement.'
|
||||
);
|
||||
|
||||
$targetPersister = $this->uow->getEntityPersister($targetEntity);
|
||||
assert($targetPersister instanceof CachedEntityPersister);
|
||||
$targetRegion = $targetPersister->getCacheRegion();
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
@@ -45,14 +29,14 @@ interface CachedCollectionPersister extends CachedPersister, CollectionPersister
|
||||
/**
|
||||
* Loads a collection from cache
|
||||
*
|
||||
* @return PersistentCollection|null
|
||||
* @return mixed[]|null
|
||||
*/
|
||||
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key);
|
||||
|
||||
/**
|
||||
* Stores a collection into cache
|
||||
*
|
||||
* @param array|mixed[]|Collection $elements
|
||||
* @param mixed[]|Collection $elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -1,29 +1,13 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
|
||||
use function spl_object_hash;
|
||||
use function spl_object_id;
|
||||
|
||||
class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
{
|
||||
@@ -65,7 +49,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
|
||||
$this->persister->delete($collection);
|
||||
|
||||
$this->queuedCache['delete'][spl_object_hash($collection)] = $key;
|
||||
$this->queuedCache['delete'][spl_object_id($collection)] = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,14 +71,14 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
if ($isDirty && ! $isInitialized || isset($this->association['orderBy'])) {
|
||||
$this->persister->update($collection);
|
||||
|
||||
$this->queuedCache['delete'][spl_object_hash($collection)] = $key;
|
||||
$this->queuedCache['delete'][spl_object_id($collection)] = $key;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->persister->update($collection);
|
||||
|
||||
$this->queuedCache['update'][spl_object_hash($collection)] = [
|
||||
$this->queuedCache['update'][spl_object_id($collection)] = [
|
||||
'key' => $key,
|
||||
'list' => $collection,
|
||||
];
|
||||
|
||||
@@ -1,27 +1,11 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\ORM\Cache\CacheException;
|
||||
use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyCollection;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
|
||||
class ReadOnlyCachedCollectionPersister extends NonStrictReadWriteCachedCollectionPersister
|
||||
@@ -32,7 +16,10 @@ class ReadOnlyCachedCollectionPersister extends NonStrictReadWriteCachedCollecti
|
||||
public function update(PersistentCollection $collection)
|
||||
{
|
||||
if ($collection->isDirty() && $collection->getSnapshot()) {
|
||||
throw CacheException::updateReadOnlyCollection(ClassUtils::getClass($collection->getOwner()), $this->association['fieldName']);
|
||||
throw CannotUpdateReadOnlyCollection::fromEntityAndField(
|
||||
ClassUtils::getClass($collection->getOwner()),
|
||||
$this->association['fieldName']
|
||||
);
|
||||
}
|
||||
|
||||
parent::update($collection);
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
|
||||
@@ -26,15 +10,12 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
|
||||
use function spl_object_hash;
|
||||
use function spl_object_id;
|
||||
|
||||
class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
{
|
||||
/**
|
||||
* @param CollectionPersister $persister The collection persister that will be cached.
|
||||
* @param ConcurrentRegion $region The collection region.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param mixed[] $association The association mapping.
|
||||
* @param mixed[] $association The association mapping.
|
||||
*/
|
||||
public function __construct(CollectionPersister $persister, ConcurrentRegion $region, EntityManagerInterface $em, array $association)
|
||||
{
|
||||
@@ -96,7 +77,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
return;
|
||||
}
|
||||
|
||||
$this->queuedCache['delete'][spl_object_hash($collection)] = [
|
||||
$this->queuedCache['delete'][spl_object_id($collection)] = [
|
||||
'key' => $key,
|
||||
'lock' => $lock,
|
||||
];
|
||||
@@ -124,7 +105,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
return;
|
||||
}
|
||||
|
||||
$this->queuedCache['update'][spl_object_hash($collection)] = [
|
||||
$this->queuedCache['update'][spl_object_id($collection)] = [
|
||||
'key' => $key,
|
||||
'lock' => $lock,
|
||||
];
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
@@ -57,7 +41,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
/** @var ClassMetadata */
|
||||
protected $class;
|
||||
|
||||
/** @var mixed[] */
|
||||
/** @var mixed[] */
|
||||
protected $queuedCache = [];
|
||||
|
||||
/** @var Region */
|
||||
@@ -267,8 +251,8 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
* @param string $query
|
||||
* @param string[]|Criteria $criteria
|
||||
* @param string[] $orderBy
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -373,9 +357,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
$cached = $queryCache->put($queryKey, $rsm, [$result]);
|
||||
|
||||
if ($this->cacheLogger) {
|
||||
if ($result) {
|
||||
$this->cacheLogger->queryCacheMiss($this->regionName, $queryKey);
|
||||
}
|
||||
$this->cacheLogger->queryCacheMiss($this->regionName, $queryKey);
|
||||
|
||||
if ($cached) {
|
||||
$this->cacheLogger->queryCachePut($this->regionName, $queryKey);
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
|
||||
@@ -1,27 +1,11 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
use Doctrine\Common\Util\ClassUtils;
|
||||
use Doctrine\ORM\Cache\CacheException;
|
||||
use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyEntity;
|
||||
|
||||
/**
|
||||
* Specific read-only region entity persister
|
||||
@@ -33,6 +17,6 @@ class ReadOnlyCachedEntityPersister extends NonStrictReadWriteCachedEntityPersis
|
||||
*/
|
||||
public function update($entity)
|
||||
{
|
||||
throw CacheException::updateReadOnlyEntity(ClassUtils::getClass($entity));
|
||||
throw CannotUpdateReadOnlyEntity::fromEntity(ClassUtils::getClass($entity));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Persister\Entity;
|
||||
|
||||
@@ -31,12 +15,6 @@ use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
*/
|
||||
class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
{
|
||||
/**
|
||||
* @param EntityPersister $persister The entity persister to cache.
|
||||
* @param ConcurrentRegion $region The entity cache region.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param ClassMetadata $class The entity metadata.
|
||||
*/
|
||||
public function __construct(EntityPersister $persister, ConcurrentRegion $region, EntityManagerInterface $em, ClassMetadata $class)
|
||||
{
|
||||
parent::__construct($persister, $region, $em, $class);
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -28,22 +12,24 @@ use function microtime;
|
||||
class QueryCacheEntry implements CacheEntry
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* List of entity identifiers
|
||||
*
|
||||
* @var array<string, mixed> List of entity identifiers
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $result;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* Time creation of this cache entry
|
||||
*
|
||||
* @var float Time creation of this cache entry
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var float
|
||||
*/
|
||||
public $time;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $result
|
||||
* @param float $time
|
||||
* @param float|null $time
|
||||
*/
|
||||
public function __construct($result, $time = null)
|
||||
{
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
@@ -28,38 +12,38 @@ use Doctrine\ORM\Cache;
|
||||
class QueryCacheKey extends CacheKey
|
||||
{
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* Cache key lifetime
|
||||
*
|
||||
* @var int Cache key lifetime
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var int
|
||||
*/
|
||||
public $lifetime;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
* Cache mode
|
||||
*
|
||||
* @var int Cache mode (Doctrine\ORM\Cache::MODE_*)
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var int
|
||||
* @psalm-var Cache::MODE_*
|
||||
*/
|
||||
public $cacheMode;
|
||||
|
||||
/**
|
||||
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
|
||||
*
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var TimestampCacheKey|null
|
||||
*/
|
||||
public $timestampKey;
|
||||
|
||||
/**
|
||||
* @param string $hash Result cache id
|
||||
* @param int $lifetime Query lifetime
|
||||
* @param int $cacheMode Query cache mode
|
||||
* @psalm-param Cache::MODE_* $cacheMode
|
||||
*/
|
||||
public function __construct(
|
||||
$hash,
|
||||
$lifetime = 0,
|
||||
$cacheMode = Cache::MODE_NORMAL,
|
||||
string $cacheId,
|
||||
int $lifetime = 0,
|
||||
int $cacheMode = Cache::MODE_NORMAL,
|
||||
?TimestampCacheKey $timestampKey = null
|
||||
) {
|
||||
$this->hash = $hash;
|
||||
$this->hash = $cacheId;
|
||||
$this->lifetime = $lifetime;
|
||||
$this->cacheMode = $cacheMode;
|
||||
$this->timestampKey = $timestampKey;
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user