mirror of
https://github.com/doctrine/orm.git
synced 2026-03-25 23:42:19 +01:00
Compare commits
292 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
495cd06b9a | ||
|
|
fd7a14ad22 | ||
|
|
0d3ce5d4f8 | ||
|
|
f01d107edc | ||
|
|
3cc30c4024 | ||
|
|
d2de4ec03c | ||
|
|
64ee76e94e | ||
|
|
8e20e1598e | ||
|
|
24df74d61d | ||
|
|
442f073d25 | ||
|
|
a5161e9485 | ||
|
|
ddc7d953b9 | ||
|
|
db51ed4f4c | ||
|
|
6d27797b2e | ||
|
|
89250b8ca2 | ||
|
|
f7e4b61459 | ||
|
|
6b0afdbd58 | ||
|
|
d3cf17b26d | ||
|
|
bc61d7d21e | ||
|
|
5213228a64 | ||
|
|
dca7ddf969 | ||
|
|
e781639812 | ||
|
|
7848417488 | ||
|
|
56e5856ad7 | ||
|
|
b5987ad29a | ||
|
|
385bdd33f1 | ||
|
|
8c513a6523 | ||
|
|
1413b496d7 | ||
|
|
3b3056f910 | ||
|
|
fa5c37e972 | ||
|
|
f3e36debfe | ||
|
|
ca7abd04a2 | ||
|
|
a555626150 | ||
|
|
ec7a8a7a0f | ||
|
|
e94fa8588d | ||
|
|
f26946b477 | ||
|
|
efc83bce8e | ||
|
|
450cae2caa | ||
|
|
81ddeb426c | ||
|
|
42e63bf358 | ||
|
|
4978e0e336 | ||
|
|
eee87c376d | ||
|
|
0b9060c728 | ||
|
|
514f6b8c28 | ||
|
|
c1018fe299 | ||
|
|
075824f5b5 | ||
|
|
d6f4834476 | ||
|
|
9dadffe270 | ||
|
|
b6e7e6d723 | ||
|
|
710937d6f8 | ||
|
|
5d2d6642c8 | ||
|
|
4d56711d8c | ||
|
|
a157bc3fb3 | ||
|
|
1aeab391c7 | ||
|
|
a4ecd02349 | ||
|
|
bb21865cba | ||
|
|
606da9280d | ||
|
|
21708e43c4 | ||
|
|
8c59828f6c | ||
|
|
0877ecbe56 | ||
|
|
8eb69922e6 | ||
|
|
e9b6fd89a4 | ||
|
|
01a14327d2 | ||
|
|
4887359827 | ||
|
|
2df1071e7a | ||
|
|
5afe9b80a8 | ||
|
|
7fc359c2bb | ||
|
|
853b9f75ae | ||
|
|
584c4aeed1 | ||
|
|
44d2a83e09 | ||
|
|
c9c5157fda | ||
|
|
dba90c1a91 | ||
|
|
5f079c2061 | ||
|
|
55d477dc50 | ||
|
|
4da8d3be96 | ||
|
|
4aadba65ce | ||
|
|
814d8d4d39 | ||
|
|
dc411954ad | ||
|
|
da29eb675c | ||
|
|
b17e52ba6b | ||
|
|
7ef4afc688 | ||
|
|
4e138903d0 | ||
|
|
efb50b9bdd | ||
|
|
70bcff7410 | ||
|
|
1989531d4f | ||
|
|
f778d8cf98 | ||
|
|
18b32ab9db | ||
|
|
d738ecfcfe | ||
|
|
aa3ff458c7 | ||
|
|
f76bab2b73 | ||
|
|
0e06d6b67d | ||
|
|
5114dcee0b | ||
|
|
8bc74c624a | ||
|
|
6c0a5ecbf9 | ||
|
|
5f6501f842 | ||
|
|
4c3bd20801 | ||
|
|
f2abf6143b | ||
|
|
338deacb58 | ||
|
|
829d5fbb9f | ||
|
|
d220494edc | ||
|
|
c235901544 | ||
|
|
ba089e551a | ||
|
|
ee0b3f214d | ||
|
|
930fa831b2 | ||
|
|
98b404875f | ||
|
|
fcc5c106b4 | ||
|
|
5132f0deb0 | ||
|
|
fe8e313731 | ||
|
|
41f704cd96 | ||
|
|
1adb5c0c70 | ||
|
|
e5174af669 | ||
|
|
c3106f9fe7 | ||
|
|
cbf45dd97e | ||
|
|
3c0d140e52 | ||
|
|
33675ff4a9 | ||
|
|
5c74795893 | ||
|
|
3827dd769e | ||
|
|
6c9b29f237 | ||
|
|
2afe2dc8af | ||
|
|
cc3d872b95 | ||
|
|
8961bfe90c | ||
|
|
15e3a7e861 | ||
|
|
65dc154ce5 | ||
|
|
1280e005b6 | ||
|
|
79f53d5dae | ||
|
|
caaa0d6192 | ||
|
|
68d3a63957 | ||
|
|
bf2937e63a | ||
|
|
76b8a215c2 | ||
|
|
b163cea61c | ||
|
|
ed212ab924 | ||
|
|
dd0e02e912 | ||
|
|
aad875eea1 | ||
|
|
84ab535e56 | ||
|
|
a72a0c3597 | ||
|
|
6217285544 | ||
|
|
330c0bc67e | ||
|
|
b5595ca041 | ||
|
|
4dfbe13897 | ||
|
|
b64e1c9b1f | ||
|
|
b779b112f3 | ||
|
|
bf449bef7d | ||
|
|
152f91fa33 | ||
|
|
14d1eb5340 | ||
|
|
04e08640fb | ||
|
|
aa27b3a35f | ||
|
|
d76fc4ebf6 | ||
|
|
da0998c401 | ||
|
|
ae60cf005f | ||
|
|
ddd3066bc4 | ||
|
|
6662195936 | ||
|
|
cc011d8215 | ||
|
|
d831c126c9 | ||
|
|
10eae1a7ff | ||
|
|
d951aa05b9 | ||
|
|
be297b9fd3 | ||
|
|
125e18cf24 | ||
|
|
8fba9d6868 | ||
|
|
7f4f1cda71 | ||
|
|
4e137f77a5 | ||
|
|
a33aa15c79 | ||
|
|
255ce51526 | ||
|
|
1c905b0e0a | ||
|
|
7901790b97 | ||
|
|
cef1d2d740 | ||
|
|
8126882305 | ||
|
|
a9513692cb | ||
|
|
52c3d9d82a | ||
|
|
2f46e5a130 | ||
|
|
a3fa1d7faa | ||
|
|
c7c57be0c2 | ||
|
|
721794fb9c | ||
|
|
38e47fdeab | ||
|
|
9ac063d879 | ||
|
|
b52a8f8b9e | ||
|
|
70477d81e9 | ||
|
|
1b2771f964 | ||
|
|
9bc6f5b4ac | ||
|
|
9766b6b03e | ||
|
|
37c8953015 | ||
|
|
60c625be17 | ||
|
|
8b0d6a13c2 | ||
|
|
a7ac6ff8d9 | ||
|
|
222d544b0c | ||
|
|
a199ca3002 | ||
|
|
6f1fd7a81e | ||
|
|
2af6e4db38 | ||
|
|
b48dafded8 | ||
|
|
ffe1550a68 | ||
|
|
eef5a1db81 | ||
|
|
c2d053d185 | ||
|
|
77822d623e | ||
|
|
7b5fafffbe | ||
|
|
aba8d74017 | ||
|
|
a056552db9 | ||
|
|
1142a396d3 | ||
|
|
f01b7d254d | ||
|
|
ed34327941 | ||
|
|
1ea8424e07 | ||
|
|
b42cf99402 | ||
|
|
ba9f51a363 | ||
|
|
1ae74b8ec5 | ||
|
|
a64f315dfe | ||
|
|
6ca319a6f4 | ||
|
|
fceb279947 | ||
|
|
2977933119 | ||
|
|
5ac6fadf29 | ||
|
|
e59ed88251 | ||
|
|
a16aeaeac8 | ||
|
|
fca1ef78a7 | ||
|
|
a78e5bcf65 | ||
|
|
09b4a75ed3 | ||
|
|
b984b567b8 | ||
|
|
92c56164ee | ||
|
|
b2707509fc | ||
|
|
1d02139d2a | ||
|
|
7ed28dba50 | ||
|
|
f215515bab | ||
|
|
ffbfbfcda1 | ||
|
|
4a30f622ec | ||
|
|
aec3556502 | ||
|
|
33a19f1bf3 | ||
|
|
b6669746b7 | ||
|
|
25bd41a504 | ||
|
|
04573fc283 | ||
|
|
82362ee65e | ||
|
|
9ff0440aac | ||
|
|
2c40e917c8 | ||
|
|
5c06d46874 | ||
|
|
24c4ac4dd8 | ||
|
|
4fad7a1190 | ||
|
|
f36a8c879c | ||
|
|
fa4b945b94 | ||
|
|
7814cbf4ec | ||
|
|
979b3dcb8d | ||
|
|
8efdcb0555 | ||
|
|
3810a0b6f9 | ||
|
|
c9b644dced | ||
|
|
ae6de13c01 | ||
|
|
072c40357f | ||
|
|
ca94e82828 | ||
|
|
db0b9d13c6 | ||
|
|
6c17e47624 | ||
|
|
83d56d75e1 | ||
|
|
d593c33ffa | ||
|
|
6c925f5b60 | ||
|
|
82bf68d482 | ||
|
|
2ee936acb4 | ||
|
|
843bff4971 | ||
|
|
d679292861 | ||
|
|
65687821a7 | ||
|
|
ca0dffb53e | ||
|
|
01028cf3b8 | ||
|
|
84bfe7cbb9 | ||
|
|
1b3978e8c9 | ||
|
|
7f783b59c8 | ||
|
|
68662f5920 | ||
|
|
769b161dff | ||
|
|
9857cf971b | ||
|
|
f73dae9bc4 | ||
|
|
1c357b9fb3 | ||
|
|
3d031ed541 | ||
|
|
15ed97b7b1 | ||
|
|
9fd4af23e1 | ||
|
|
4206f01e7b | ||
|
|
7d4052c9e7 | ||
|
|
fc6feb5938 | ||
|
|
89b98bdff9 | ||
|
|
37572802cc | ||
|
|
a5bdc619c7 | ||
|
|
65a7c8882f | ||
|
|
2d6295c9db | ||
|
|
f0616626e0 | ||
|
|
a8ef69dbe6 | ||
|
|
c0a7317e8d | ||
|
|
843b0fcc16 | ||
|
|
b56de5b0e2 | ||
|
|
0b35e637b8 | ||
|
|
277614d9c2 | ||
|
|
29b8b0bffb | ||
|
|
b7ba018f0a | ||
|
|
72b1bf0c02 | ||
|
|
70241d3407 | ||
|
|
1d5d47964c | ||
|
|
c9c4203a1e | ||
|
|
091da8c420 | ||
|
|
515a3d8b8b | ||
|
|
603ab9a185 | ||
|
|
10d27c18ea | ||
|
|
ae9fb8ca21 | ||
|
|
c7f2a1d580 | ||
|
|
b3f441cb8b |
@@ -12,21 +12,27 @@
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.15",
|
||||
"branchName": "2.15.x",
|
||||
"slug": "2.15",
|
||||
"name": "2.16",
|
||||
"branchName": "2.16.x",
|
||||
"slug": "2.16",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.14",
|
||||
"branchName": "2.14.x",
|
||||
"slug": "2.14",
|
||||
"name": "2.15",
|
||||
"branchName": "2.15.x",
|
||||
"slug": "2.15",
|
||||
"current": true,
|
||||
"aliases": [
|
||||
"current",
|
||||
"stable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "2.14",
|
||||
"branchName": "2.14.x",
|
||||
"slug": "2.14",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.13",
|
||||
"branchName": "2.13.x",
|
||||
|
||||
51
.github/workflows/documentation.yml
vendored
Normal file
51
.github/workflows/documentation.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: "Documentation"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/documentation.yml
|
||||
- docs/**
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/documentation.yml
|
||||
- docs/**
|
||||
|
||||
jobs:
|
||||
validate-with-guides:
|
||||
name: "Validate documentation with phpDocumentor/guides"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v3"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.2"
|
||||
|
||||
- name: "Remove existing composer file"
|
||||
run: "rm composer.json"
|
||||
|
||||
- name: "Require phpdocumentor/guides-cli"
|
||||
run: "composer require --dev phpdocumentor/guides-cli dev-main@dev --no-update"
|
||||
|
||||
- name: "Configure minimum stability"
|
||||
run: "composer config minimum-stability dev"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
- name: "Add dummy title to the sidebar"
|
||||
run: |
|
||||
printf '%s\n%s\n\n%s\n' "Dummy title" "===========" "$(cat docs/en/sidebar.rst)" > docs/en/sidebar.rst
|
||||
|
||||
- name: "Run guides-cli"
|
||||
run: "vendor/bin/guides -vvv --no-progress docs/en /tmp/test 2>&1 | ( ! grep WARNING )"
|
||||
@@ -40,6 +40,11 @@ cd orm
|
||||
composer install
|
||||
```
|
||||
|
||||
You will also need to enable the PHP extension that provides the SQLite driver
|
||||
for PDO: `pdo_sqlite`. How to do so depends on your system, but checking that it
|
||||
is enabled can universally be done with `php -m`: that command should list the
|
||||
extension.
|
||||
|
||||
To run the testsuite against another database, copy the ``phpunit.xml.dist``
|
||||
to for example ``mysql.phpunit.xml`` and edit the parameters. You can
|
||||
take a look at the ``ci/github/phpunit`` directory for some examples. Then run:
|
||||
|
||||
22
README.md
22
README.md
@@ -1,7 +1,7 @@
|
||||
| [3.0.x][3.0] | [2.14.x][2.14] | [2.13.x][2.13] |
|
||||
| [3.0.x][3.0] | [2.16.x][2.16] | [2.15.x][2.15] |
|
||||
|:----------------:|:----------------:|:----------:|
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.14 image]][2.14] | [![Build status][2.13 image]][2.13] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.14 coverage image]][2.14 coverage] | [![Coverage Status][2.13 coverage image]][2.13 coverage] |
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.16 image]][2.16] | [![Build status][2.15 image]][2.15] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.16 coverage image]][2.16 coverage] | [![Coverage Status][2.15 coverage image]][2.15 coverage] |
|
||||
|
||||
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
|
||||
|
||||
@@ -22,11 +22,11 @@ without requiring unnecessary code duplication.
|
||||
[3.0]: https://github.com/doctrine/orm/tree/3.0.x
|
||||
[3.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.0.x/graph/badge.svg
|
||||
[3.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.0.x
|
||||
[2.14 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.14.x
|
||||
[2.14]: https://github.com/doctrine/orm/tree/2.14.x
|
||||
[2.14 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.14.x/graph/badge.svg
|
||||
[2.14 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.14.x
|
||||
[2.13 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.13.x
|
||||
[2.13]: https://github.com/doctrine/orm/tree/2.13.x
|
||||
[2.13 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.13.x/graph/badge.svg
|
||||
[2.13 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.13.x
|
||||
[2.16 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.16.x
|
||||
[2.16]: https://github.com/doctrine/orm/tree/2.16.x
|
||||
[2.16 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.16.x/graph/badge.svg
|
||||
[2.16 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.16.x
|
||||
[2.15 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.15.x
|
||||
[2.15]: https://github.com/doctrine/orm/tree/2.15.x
|
||||
[2.15 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.15.x/graph/badge.svg
|
||||
[2.15 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.15.x
|
||||
|
||||
58
UPGRADE.md
58
UPGRADE.md
@@ -1,3 +1,61 @@
|
||||
# Upgrade to 2.16
|
||||
|
||||
## Deprecated `\Doctrine\ORM\Internal\CommitOrderCalculator` and related classes
|
||||
|
||||
With changes made to the commit order computation, the internal classes
|
||||
`\Doctrine\ORM\Internal\CommitOrderCalculator`, `\Doctrine\ORM\Internal\CommitOrder\Edge`,
|
||||
`\Doctrine\ORM\Internal\CommitOrder\Vertex` and `\Doctrine\ORM\Internal\CommitOrder\VertexState`
|
||||
have been deprecated and will be removed in ORM 3.0.
|
||||
|
||||
## Deprecated returning post insert IDs from `EntityPersister::executeInserts()`
|
||||
|
||||
Persisters implementing `\Doctrine\ORM\Persisters\Entity\EntityPersister` should no longer
|
||||
return an array of post insert IDs from their `::executeInserts()` method. Make the
|
||||
persister call `Doctrine\ORM\UnitOfWork::assignPostInsertId()` instead.
|
||||
|
||||
## Changing the way how reflection-based mapping drivers report fields, deprecated the "old" mode
|
||||
|
||||
In ORM 3.0, a change will be made regarding how the `AttributeDriver` reports field mappings.
|
||||
This change is necessary to be able to detect (and reject) some invalid mapping configurations.
|
||||
|
||||
To avoid surprises during 2.x upgrades, the new mode is opt-in. It can be activated on the
|
||||
`AttributeDriver` and `AnnotationDriver` by setting the `$reportFieldsWhereDeclared`
|
||||
constructor parameter to `true`. It will cause `MappingException`s to be thrown when invalid
|
||||
configurations are detected.
|
||||
|
||||
Not enabling the new mode will cause a deprecation notice to be raised. In ORM 3.0,
|
||||
only the new mode will be available.
|
||||
|
||||
# Upgrade to 2.15
|
||||
|
||||
## Deprecated configuring `JoinColumn` on the inverse side of one-to-one associations
|
||||
|
||||
For one-to-one associations, the side using the `mappedBy` attribute is the inverse side.
|
||||
The owning side is the entity with the table containing the foreign key. Using `JoinColumn`
|
||||
configuration on the _inverse_ side now triggers a deprecation notice and will be an error
|
||||
in 3.0.
|
||||
|
||||
## Deprecated overriding fields or associations not declared in mapped superclasses
|
||||
|
||||
As stated in the documentation, fields and associations may only be overridden when being inherited
|
||||
from mapped superclasses. Overriding them for parent entity classes now triggers a deprecation notice
|
||||
and will be an error in 3.0.
|
||||
|
||||
## Deprecated undeclared entity inheritance
|
||||
|
||||
As soon as an entity class inherits from another entity class, inheritance has to
|
||||
be declared by adding the appropriate configuration for the root entity.
|
||||
|
||||
## Deprecated stubs for "concrete table inheritance"
|
||||
|
||||
This third way of mapping class inheritance was never implemented. Code stubs are
|
||||
now deprecated and will be removed in 3.0.
|
||||
|
||||
* `\Doctrine\ORM\Mapping\ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS` constant
|
||||
* `\Doctrine\ORM\Mapping\ClassMetadataInfo::isInheritanceTypeTablePerClass()` method
|
||||
* Using `TABLE_PER_CLASS` as the value for the `InheritanceType` attribute or annotation
|
||||
or in XML configuration files.
|
||||
|
||||
# Upgrade to 2.14
|
||||
|
||||
## Deprecated `Doctrine\ORM\Persisters\Exception\UnrecognizedField::byName($field)` method.
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
"composer-runtime-api": "^2",
|
||||
"ext-ctype": "*",
|
||||
"doctrine/cache": "^1.12.1 || ^2.1.1",
|
||||
"doctrine/collections": "^1.5 || ^2.0",
|
||||
"doctrine/collections": "^1.5 || ^2.1",
|
||||
"doctrine/common": "^3.0.3",
|
||||
"doctrine/dbal": "^2.13.1 || ^3.2",
|
||||
"doctrine/deprecations": "^0.5.3 || ^1",
|
||||
"doctrine/event-manager": "^1.2 || ^2",
|
||||
"doctrine/inflector": "^1.4 || ^2.0",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
"doctrine/lexer": "^1.2.3 || ^2",
|
||||
"doctrine/instantiator": "^1.3 || ^2",
|
||||
"doctrine/lexer": "^2",
|
||||
"doctrine/persistence": "^2.4 || ^3",
|
||||
"psr/cache": "^1 || ^2 || ^3",
|
||||
"symfony/console": "^4.2 || ^5.0 || ^6.0",
|
||||
@@ -40,16 +40,16 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "^1.13 || ^2",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^11.0",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^12.0",
|
||||
"phpbench/phpbench": "^0.16.10 || ^1.0",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.10.6",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.10.25",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.7.2",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
|
||||
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2",
|
||||
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
|
||||
"vimeo/psalm": "4.30.0 || 5.9.0"
|
||||
"vimeo/psalm": "4.30.0 || 5.13.1"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/annotations": "<1.13 || >= 3.0"
|
||||
|
||||
@@ -18,8 +18,8 @@ Doctrine ORM don't panic. You can get help from different sources:
|
||||
- Report a bug on `GitHub <https://github.com/doctrine/orm/issues>`_.
|
||||
- On `StackOverflow <https://stackoverflow.com/questions/tagged/doctrine-orm>`_
|
||||
|
||||
If you need more structure over the different topics you can browse the :doc:`table
|
||||
of contents <toc>`.
|
||||
If you need more structure over the different topics you can browse the table
|
||||
of contents.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
@@ -34,32 +34,32 @@ Mapping Objects onto a Database
|
||||
-------------------------------
|
||||
|
||||
* **Mapping**:
|
||||
:doc:`Objects <reference/basic-mapping>` |
|
||||
:doc:`Associations <reference/association-mapping>` |
|
||||
:doc:`Objects <reference/basic-mapping>` \|
|
||||
:doc:`Associations <reference/association-mapping>` \|
|
||||
:doc:`Inheritance <reference/inheritance-mapping>`
|
||||
|
||||
* **Drivers**:
|
||||
:doc:`Docblock Annotations <reference/annotations-reference>` |
|
||||
:doc:`Attributes <reference/attributes-reference>` |
|
||||
:doc:`XML <reference/xml-mapping>` |
|
||||
:doc:`YAML <reference/yaml-mapping>` |
|
||||
:doc:`Docblock Annotations <reference/annotations-reference>` \|
|
||||
:doc:`Attributes <reference/attributes-reference>` \|
|
||||
:doc:`XML <reference/xml-mapping>` \|
|
||||
:doc:`YAML <reference/yaml-mapping>` \|
|
||||
:doc:`PHP <reference/php-mapping>`
|
||||
|
||||
Working with Objects
|
||||
--------------------
|
||||
|
||||
* **Basic Reference**:
|
||||
:doc:`Entities <reference/working-with-objects>` |
|
||||
:doc:`Associations <reference/working-with-associations>` |
|
||||
:doc:`Entities <reference/working-with-objects>` \|
|
||||
:doc:`Associations <reference/working-with-associations>` \|
|
||||
:doc:`Events <reference/events>`
|
||||
|
||||
* **Query Reference**:
|
||||
:doc:`DQL <reference/dql-doctrine-query-language>` |
|
||||
:doc:`QueryBuilder <reference/query-builder>` |
|
||||
:doc:`DQL <reference/dql-doctrine-query-language>` \|
|
||||
:doc:`QueryBuilder <reference/query-builder>` \|
|
||||
:doc:`Native SQL <reference/native-sql>`
|
||||
|
||||
* **Internals**:
|
||||
:doc:`Internals explained <reference/unitofwork>` |
|
||||
:doc:`Internals explained <reference/unitofwork>` \|
|
||||
:doc:`Associations <reference/unitofwork-associations>`
|
||||
|
||||
Advanced Topics
|
||||
@@ -102,20 +102,20 @@ Cookbook
|
||||
--------
|
||||
|
||||
* **Patterns**:
|
||||
:doc:`Aggregate Fields <cookbook/aggregate-fields>` |
|
||||
:doc:`Decorator Pattern <cookbook/decorator-pattern>` |
|
||||
:doc:`Aggregate Fields <cookbook/aggregate-fields>` \|
|
||||
:doc:`Decorator Pattern <cookbook/decorator-pattern>` \|
|
||||
:doc:`Strategy Pattern <cookbook/strategy-cookbook-introduction>`
|
||||
|
||||
* **DQL Extension Points**:
|
||||
:doc:`DQL Custom Walkers <cookbook/dql-custom-walkers>` |
|
||||
:doc:`DQL Custom Walkers <cookbook/dql-custom-walkers>` \|
|
||||
:doc:`DQL User-Defined-Functions <cookbook/dql-user-defined-functions>`
|
||||
|
||||
* **Implementation**:
|
||||
:doc:`Array Access <cookbook/implementing-arrayaccess-for-domain-objects>` |
|
||||
:doc:`Notify ChangeTracking Example <cookbook/implementing-the-notify-changetracking-policy>` |
|
||||
:doc:`Working with DateTime <cookbook/working-with-datetime>` |
|
||||
:doc:`Validation <cookbook/validation-of-entities>` |
|
||||
:doc:`Entities in the Session <cookbook/entities-in-session>` |
|
||||
:doc:`Array Access <cookbook/implementing-arrayaccess-for-domain-objects>` \|
|
||||
:doc:`Notify ChangeTracking Example <cookbook/implementing-the-notify-changetracking-policy>` \|
|
||||
:doc:`Working with DateTime <cookbook/working-with-datetime>` \|
|
||||
:doc:`Validation <cookbook/validation-of-entities>` \|
|
||||
:doc:`Entities in the Session <cookbook/entities-in-session>` \|
|
||||
:doc:`Keeping your Modules independent <cookbook/resolve-target-entity-listener>`
|
||||
|
||||
* **Hidden Gems**
|
||||
@@ -124,5 +124,3 @@ Cookbook
|
||||
* **Custom Datatypes**
|
||||
:doc:`MySQL Enums <cookbook/mysql-enums>`
|
||||
:doc:`Advanced Field Value Conversion <cookbook/advanced-field-value-conversion-using-custom-mapping-types>`
|
||||
|
||||
.. include:: toc.rst
|
||||
|
||||
@@ -311,10 +311,12 @@ Reference Proxies
|
||||
|
||||
The method ``EntityManager#getReference($entityName, $identifier)``
|
||||
lets you obtain a reference to an entity for which the identifier
|
||||
is known, without loading that entity from the database. This is
|
||||
useful, for example, as a performance enhancement, when you want to
|
||||
establish an association to an entity for which you have the
|
||||
identifier. You could simply do this:
|
||||
is known, without necessarily loading that entity from the database.
|
||||
This is useful, for example, as a performance enhancement, when you
|
||||
want to establish an association to an entity for which you have the
|
||||
identifier.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -324,15 +326,33 @@ identifier. You could simply do this:
|
||||
$item = $em->getReference('MyProject\Model\Item', $itemId);
|
||||
$cart->addItem($item);
|
||||
|
||||
Here, we added an Item to a Cart without loading the Item from the
|
||||
database. If you access any state that isn't yet available in the
|
||||
Item instance, the proxying mechanism would fully initialize the
|
||||
object's state transparently from the database. Here
|
||||
$item is actually an instance of the proxy class that was generated
|
||||
for the Item class but your code does not need to care. In fact it
|
||||
**should not care**. Proxy objects should be transparent to your
|
||||
Whether the object being returned from ``EntityManager#getReference()``
|
||||
is a proxy or a direct instance of the entity class may depend on different
|
||||
factors, including whether the entity has already been loaded into memory
|
||||
or entity inheritance being used. But your code does not need to care
|
||||
and in fact it **should not care**. Proxy objects should be transparent to your
|
||||
code.
|
||||
|
||||
When using the ``EntityManager#getReference()`` method, you need to be aware
|
||||
of a few peculiarities.
|
||||
|
||||
At the best case, the ORM can avoid querying the database at all. But, that
|
||||
also means that this method will not throw an exception when an invalid value
|
||||
for the ``$identifier`` parameter is passed. ``$identifier`` values are
|
||||
not checked and there is no guarantee that the requested entity instance even
|
||||
exists – the method will still return a proxy object.
|
||||
|
||||
Its only when the proxy has to be fully initialized or associations cannot
|
||||
be written to the database that invalid ``$identifier`` values may lead to
|
||||
exceptions.
|
||||
|
||||
The ``EntityManager#getReference()`` is mostly useful when you only
|
||||
need a reference to some entity to make an association, like in the example
|
||||
above. In that case, it can save you from loading data from the database
|
||||
that you don't need. But remember – as soon as you read any property values
|
||||
besides those making up the ID, a database request will be made to initialize
|
||||
all fields.
|
||||
|
||||
Association proxies
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -545,12 +545,12 @@ has meaning in the SchemaTool schema generation context.
|
||||
Required attributes:
|
||||
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **fields**: Array of fields. Exactly one of **fields**, **columns** is required.
|
||||
- **columns**: Array of columns. Exactly one of **fields**, **columns** is required.
|
||||
|
||||
Optional attributes:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
@@ -1316,12 +1316,12 @@ context.
|
||||
Required attributes:
|
||||
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **fields**: Array of fields. Exactly one of **fields**, **columns** is required.
|
||||
- **columns**: Array of columns. Exactly one of **fields**, **columns** is required.
|
||||
|
||||
Optional attributes:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
|
||||
@@ -102,7 +102,7 @@ persistent entity state and mapping information for its subclasses,
|
||||
but which is not itself an entity.
|
||||
|
||||
Mapped superclasses are explained in greater detail in the chapter
|
||||
on :doc:`inheritance mapping <reference/inheritance-mapping>`.
|
||||
on :doc:`inheritance mapping </reference/inheritance-mapping>`.
|
||||
|
||||
Transient Classes
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -881,6 +881,15 @@ Generated MySQL Schema:
|
||||
replaced by one-to-many/many-to-one associations between the 3
|
||||
participating classes.
|
||||
|
||||
.. note::
|
||||
|
||||
For many-to-many associations, the ORM takes care of managing rows
|
||||
in the join table connecting both sides. Due to the way it deals
|
||||
with entity removals, database-level constraints may not work the
|
||||
way one might intuitively assume. Thus, be sure not to miss the section
|
||||
on :ref:`join table management <remove_object_many_to_many_join_tables>`.
|
||||
|
||||
|
||||
Many-To-Many, Bidirectional
|
||||
---------------------------
|
||||
|
||||
@@ -1019,6 +1028,15 @@ one is bidirectional.
|
||||
The MySQL schema is exactly the same as for the Many-To-Many
|
||||
uni-directional case above.
|
||||
|
||||
.. note::
|
||||
|
||||
For many-to-many associations, the ORM takes care of managing rows
|
||||
in the join table connecting both sides. Due to the way it deals
|
||||
with entity removals, database-level constraints may not work the
|
||||
way one might intuitively assume. Thus, be sure not to miss the section
|
||||
on :ref:`join table management <remove_object_many_to_many_join_tables>`.
|
||||
|
||||
|
||||
Owning and Inverse Side on a ManyToMany Association
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -368,6 +368,7 @@ Optional parameters:
|
||||
- **length**: By default this is 255.
|
||||
- **columnDefinition**: By default this is null the definition according to the type will be used. This option allows to override it.
|
||||
- **enumType**: By default this is `null`. Allows to map discriminatorColumn value to PHP enum
|
||||
- **options**: See "options" attribute on :ref:`#[Column] <attrref_column>`.
|
||||
|
||||
.. _attrref_discriminatormap:
|
||||
|
||||
@@ -539,13 +540,13 @@ has meaning in the ``SchemaTool`` schema generation context.
|
||||
|
||||
Required parameters:
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **fields**: Array of fields. Exactly one of **fields, columns** is required.
|
||||
- **columns**: Array of columns. Exactly one of **fields, columns** is required.
|
||||
|
||||
|
||||
Optional parameters:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
@@ -575,7 +576,7 @@ Example with partial indexes:
|
||||
|
||||
#[Index(name: "search_idx", columns: ["category"],
|
||||
options: [
|
||||
"where": "((category IS NOT NULL))"
|
||||
"where" => "((category IS NOT NULL))"
|
||||
]
|
||||
)]
|
||||
class ECommerceProduct
|
||||
@@ -1103,11 +1104,12 @@ context.
|
||||
|
||||
Required parameters:
|
||||
|
||||
- **name**: Name of the Index
|
||||
- **columns**: Array of columns.
|
||||
- **fields**: Array of fields (the names of the properties, used in the entity class).
|
||||
- **columns**: Array of columns (the names of the columns, used in the schema).
|
||||
|
||||
Optional parameters:
|
||||
|
||||
- **name**: Name of the Index. If not provided, a generated name will be assigned.
|
||||
- **options**: Array of platform specific options:
|
||||
|
||||
- ``where``: SQL WHERE condition to be used for partial indexes. It will
|
||||
|
||||
@@ -460,7 +460,7 @@ Here is the list of possible generation strategies:
|
||||
a new entity is passed to ``EntityManager#persist``. NONE is the
|
||||
same as leaving off the ``#[GeneratedValue]`` entirely.
|
||||
- ``CUSTOM``: With this option, you can use the ``#[CustomIdGenerator]`` attribute.
|
||||
It will allow you to pass a :doc:`class of your own to generate the identifiers.<_annref_customidgenerator>`
|
||||
It will allow you to pass a :ref:`class of your own to generate the identifiers.<annref_customidgenerator>`
|
||||
|
||||
Sequence Generator
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -86,7 +86,7 @@ with the batching strategy that was already used for bulk inserts:
|
||||
|
||||
<?php
|
||||
$batchSize = 20;
|
||||
$i = 1;
|
||||
$i = 0;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
foreach ($q->toIterable() as $user) {
|
||||
$user->increaseCredit();
|
||||
@@ -145,7 +145,7 @@ The following example shows how to do this:
|
||||
|
||||
<?php
|
||||
$batchSize = 20;
|
||||
$i = 1;
|
||||
$i = 0;
|
||||
$q = $em->createQuery('select u from MyProject\Model\User u');
|
||||
foreach($q->toIterable() as $row) {
|
||||
$em->remove($row);
|
||||
|
||||
@@ -104,7 +104,7 @@ Inside the ``ORMSetup`` methods several assumptions are made:
|
||||
In order to have ``ORMSetup`` configure the cache automatically, the library ``symfony/cache``
|
||||
has to be installed as a dependency.
|
||||
|
||||
If you want to configure Doctrine in more detail, take a look at the :doc:`Advanced Configuration <reference/advanced-configuration>` section.
|
||||
If you want to configure Doctrine in more detail, take a look at the :doc:`Advanced Configuration </reference/advanced-configuration>` section.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
@@ -1304,14 +1304,13 @@ 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(FetchMode::FETCH_ASSOC);
|
||||
return $this->_stmt->fetchAllAssociative();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1337,8 +1336,8 @@ There are situations when a query you want to execute returns a
|
||||
very large result-set that needs to be processed. All the
|
||||
previously described hydration modes completely load a result-set
|
||||
into memory which might not be feasible with large result sets. See
|
||||
the `Batch Processing <batch-processing.html>`_ section on details how
|
||||
to iterate large result sets.
|
||||
the :doc:`Batch Processing </reference/batch-processing>` section on
|
||||
details how to iterate large result sets.
|
||||
|
||||
Functions
|
||||
~~~~~~~~~
|
||||
|
||||
@@ -281,10 +281,10 @@ specific to a particular entity class's lifecycle.
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="User">
|
||||
<!-- ... -->
|
||||
<lifecycle-callbacks>
|
||||
@@ -707,8 +707,8 @@ not directly mapped by Doctrine.
|
||||
``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.
|
||||
database insert operation for that entity. A generated primary key value for
|
||||
the entity will be 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.
|
||||
|
||||
@@ -13,11 +13,10 @@ Database Schema
|
||||
How do I set the charset and collation for MySQL tables?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can't set these values with attributes, annotations or inside yml or
|
||||
xml mapping files. To make a database work with the default charset and
|
||||
collation you should configure MySQL to use it as default charset, or
|
||||
create the database with charset and collation details. This way they
|
||||
get inherited to all newly created database tables and columns.
|
||||
In your mapping configuration, the column definition (for example, the
|
||||
``#[Column]`` attribute) has an ``options`` parameter where you can specify
|
||||
the ``charset`` and ``collation``. The default values are ``utf8`` and
|
||||
``utf8_unicode_ci``, respectively.
|
||||
|
||||
Entity Classes
|
||||
--------------
|
||||
|
||||
@@ -93,3 +93,34 @@ object.
|
||||
want to refresh or reload an object after having modified a filter or the
|
||||
FilterCollection, then you should clear the EntityManager and re-fetch your
|
||||
entities, having the new rules for filtering applied.
|
||||
|
||||
|
||||
Suspending/Restoring Filters
|
||||
----------------------------
|
||||
When a filter is disabled, the instance is fully deleted and all the filter
|
||||
parameters previously set are lost. Then, if you enable it again, a new filter
|
||||
is created without the previous filter parameters. If you want to keep a filter
|
||||
(in order to use it later) but temporary disable it, you'll need to use the
|
||||
``FilterCollection#suspend($name)`` and ``FilterCollection#restore($name)``
|
||||
methods instead.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$filter = $em->getFilters()->enable("locale");
|
||||
$filter->setParameter('locale', 'en');
|
||||
|
||||
// Temporary suspend the filter
|
||||
$filter = $em->getFilters()->suspend("locale");
|
||||
|
||||
// Do things
|
||||
|
||||
// Then restore it, the locale parameter will still be set
|
||||
$filter = $em->getFilters()->restore("locale");
|
||||
|
||||
.. warning::
|
||||
If you enable a previously disabled filter, doctrine will create a new
|
||||
one without keeping any of the previously parameter set with
|
||||
``SQLFilter#setParameter()`` or ``SQLFilter#getParameterList()``. If you
|
||||
want to restore the previously disabled filter instead, you must use the
|
||||
``FilterCollection#restore($name)`` method.
|
||||
|
||||
@@ -91,7 +91,7 @@ Apply Best Practices
|
||||
A lot of the points mentioned in the Best Practices chapter will
|
||||
also positively affect the performance of Doctrine.
|
||||
|
||||
See :doc:`Best Practices <reference/best-practices>`
|
||||
See :doc:`Best Practices </reference/best-practices>`
|
||||
|
||||
Change Tracking policies
|
||||
------------------------
|
||||
|
||||
@@ -15,27 +15,37 @@ is common to multiple entity classes.
|
||||
|
||||
Mapped superclasses, just as regular, non-mapped classes, can
|
||||
appear in the middle of an otherwise mapped inheritance hierarchy
|
||||
(through Single Table Inheritance or Class Table Inheritance).
|
||||
(through Single Table Inheritance or Class Table Inheritance). They
|
||||
are not query-able, and need not have an ``#[Id]`` property.
|
||||
|
||||
No database table will be created for a mapped superclass itself,
|
||||
only for entity classes inheriting from it. Also, a mapped superclass
|
||||
need not have an ``#[Id]`` property.
|
||||
only for entity classes inheriting from it. That implies that a
|
||||
mapped superclass cannot be the ``targetEntity`` in associations.
|
||||
|
||||
In other words, a mapped superclass can use unidirectional One-To-One
|
||||
and Many-To-One associations where it is the owning side.
|
||||
Many-To-Many associations are only possible if the mapped
|
||||
superclass is only used in exactly one entity at the moment. For further
|
||||
support of inheritance, the single or joined table inheritance features
|
||||
have to be used.
|
||||
|
||||
.. note::
|
||||
|
||||
A mapped superclass cannot be an entity, it is not query-able and
|
||||
persistent relationships defined by a mapped superclass must be
|
||||
unidirectional (with an owning side only). This means that One-To-Many
|
||||
associations are not possible on a mapped superclass at all.
|
||||
Furthermore Many-To-Many associations are only possible if the
|
||||
mapped superclass is only used in exactly one entity at the moment.
|
||||
For further support of inheritance, the single or
|
||||
joined table inheritance features have to be used.
|
||||
One-To-Many associations are not generally possible on a mapped
|
||||
superclass, since they require the "many" side to hold the foreign
|
||||
key.
|
||||
|
||||
It is, however, possible to use the :doc:`ResolveTargetEntityListener </cookbook/resolve-target-entity-listener>`
|
||||
to replace references to a mapped superclass with an entity class at runtime.
|
||||
As long as there is only one entity subclass inheriting from the mapped
|
||||
superclass and all references to the mapped superclass are resolved to that
|
||||
entity class at runtime, the mapped superclass *can* use One-To-Many associations
|
||||
and be named as the ``targetEntity`` on the owning sides.
|
||||
|
||||
.. warning::
|
||||
|
||||
At least when using attributes or annotations to specify your mapping,
|
||||
it _seems_ as if you could inherit from a base class that is neither
|
||||
it *seems* as if you could inherit from a base class that is neither
|
||||
an entity nor a mapped superclass, but has properties with mapping configuration
|
||||
on them that would also be used in the inheriting class.
|
||||
|
||||
@@ -50,7 +60,7 @@ need not have an ``#[Id]`` property.
|
||||
You may be tempted to use traits to mix mapped fields or relationships
|
||||
into your entity classes to circumvent some of the limitations of
|
||||
mapped superclasses. Before doing that, please read the section on traits
|
||||
in the :doc:`Limitations and Known Issues <reference/limitations-and-known-issues>` chapter.
|
||||
in the :doc:`Limitations and Known Issues </reference/limitations-and-known-issues>` chapter.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -370,7 +380,7 @@ It is not supported to use overrides in entity inheritance scenarios.
|
||||
.. note::
|
||||
|
||||
When using traits, make sure not to miss the warnings given in the
|
||||
:doc:`Limitations and Known Issues<reference/limitations-and-known-issues>` chapter.
|
||||
:doc:`Limitations and Known Issues</reference/limitations-and-known-issues>` chapter.
|
||||
|
||||
|
||||
Association Override
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
The installation chapter has moved to :doc:`Installation and Configuration <reference/configuration>`_.
|
||||
The installation chapter has moved to :doc:`Installation and Configuration </reference/configuration>`.
|
||||
|
||||
@@ -145,7 +145,7 @@ more than two years after the initial Doctrine 2 release and the time where
|
||||
core components were designed.
|
||||
|
||||
In fact, this documentation mentions traits only in the context of
|
||||
:doc:`overriding field association mappings in subclasses <tutorials/override-field-association-mappings-in-subclasses>`.
|
||||
:doc:`overriding field association mappings in subclasses </tutorials/override-field-association-mappings-in-subclasses>`.
|
||||
Coverage of traits in test cases is practically nonexistent.
|
||||
|
||||
Thus, you should at least be aware that when using traits in your entity and
|
||||
@@ -162,14 +162,14 @@ that, some precedence and conflict resolution rules apply.
|
||||
|
||||
When it comes to loading mapping configuration, the annotation and attribute drivers
|
||||
rely on PHP reflection to inspect class properties including their docblocks.
|
||||
As long as the results are consistent with what a solution _without_ traits would
|
||||
As long as the results are consistent with what a solution *without* traits would
|
||||
have produced, this is probably fine.
|
||||
|
||||
However, to mention known limitations, it is currently not possible to use "class"
|
||||
level `annotations <https://github.com/doctrine/orm/pull/1517>` or
|
||||
level `annotations <https://github.com/doctrine/orm/pull/1517>`_ or
|
||||
`attributes <https://github.com/doctrine/orm/issues/8868>` on traits, and attempts to
|
||||
improve parser support for traits as `here <https://github.com/doctrine/annotations/pull/102>`
|
||||
or `there <https://github.com/doctrine/annotations/pull/63>` have been abandoned
|
||||
improve parser support for traits as `here <https://github.com/doctrine/annotations/pull/102>`_
|
||||
or `there <https://github.com/doctrine/annotations/pull/63>`_ have been abandoned
|
||||
due to complexity.
|
||||
|
||||
XML mapping configuration probably needs to completely re-configure or otherwise
|
||||
|
||||
@@ -123,12 +123,12 @@ the ``FileDriver`` implementation for you to extend from:
|
||||
class MyMetadataDriver extends FileDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected $_fileExtension = '.dcm.ext';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
@@ -138,7 +138,7 @@ the ``FileDriver`` implementation for you to extend from:
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function _loadMappingFile($file)
|
||||
{
|
||||
|
||||
@@ -250,6 +250,40 @@ The first parameter is the name of the column in the SQL result set
|
||||
and the second parameter is the result alias under which the value
|
||||
of the column will be placed in the transformed Doctrine result.
|
||||
|
||||
Special case: DTOs
|
||||
...................
|
||||
|
||||
You can also use ``ResultSetMapping`` to map the results of a native SQL
|
||||
query to a DTO (Data Transfer Object). This is done by adding scalar
|
||||
results for each argument of the DTO's constructor, then filling the
|
||||
``newObjectMappings`` property of the ``ResultSetMapping`` with
|
||||
information about where to map each scalar result:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
$rsm = new ResultSetMapping();
|
||||
$rsm->addScalarResult('name', 1, 'string');
|
||||
$rsm->addScalarResult('email', 2, 'string');
|
||||
$rsm->addScalarResult('city', 3, 'string');
|
||||
$rsm->newObjectMappings['name'] = [
|
||||
'className' => CmsUserDTO::class,
|
||||
'objIndex' => 0, // a result can contain many DTOs, this is the index of the DTO to map to
|
||||
'argIndex' => 0, // each scalar result can be mapped to a different argument of the DTO constructor
|
||||
];
|
||||
$rsm->newObjectMappings['email'] = [
|
||||
'className' => CmsUserDTO::class,
|
||||
'objIndex' => 0,
|
||||
'argIndex' => 1,
|
||||
];
|
||||
$rsm->newObjectMappings['city'] = [
|
||||
'className' => CmsUserDTO::class,
|
||||
'objIndex' => 0,
|
||||
'argIndex' => 2,
|
||||
];
|
||||
|
||||
|
||||
Meta results
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ The API of the ClassMetadataBuilder has the following methods with a fluent inte
|
||||
- ``addNamedQuery($name, $dqlQuery)``
|
||||
- ``setJoinedTableInheritance()``
|
||||
- ``setSingleTableInheritance()``
|
||||
- ``setDiscriminatorColumn($name, $type = 'string', $length = 255, $columnDefinition = null, $enumType = null)``
|
||||
- ``setDiscriminatorColumn($name, $type = 'string', $length = 255, $columnDefinition = null, $enumType = null, $options = [])``
|
||||
- ``addDiscriminatorMapClass($name, $class)``
|
||||
- ``setChangeTrackingPolicyDeferredExplicit()``
|
||||
- ``setChangeTrackingPolicyNotify()``
|
||||
|
||||
@@ -578,8 +578,6 @@ of DQL. It takes 3 parameters: ``$dqlPartName``, ``$dqlPart`` and
|
||||
not (no effect on the ``where`` and ``having`` DQL query parts,
|
||||
which always override all previously defined items)
|
||||
|
||||
-
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
@@ -322,7 +322,10 @@ level cache region.
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="Country">
|
||||
<cache usage="READ_ONLY" region="my_entity_region" />
|
||||
<id name="id" type="integer" column="id">
|
||||
@@ -427,7 +430,10 @@ It caches the primary keys of association and cache each element will be cached
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<entity name="State">
|
||||
|
||||
<cache usage="NONSTRICT_READ_WRITE" />
|
||||
|
||||
@@ -153,7 +153,7 @@ You need to create a class which implements ``Doctrine\ORM\Mapping\TypedFieldMap
|
||||
final class CustomEnumTypedFieldMapper implements TypedFieldMapper
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validateAndComplete(array $mapping, ReflectionProperty $field): array
|
||||
{
|
||||
|
||||
@@ -37,8 +37,8 @@ will still end up with the same reference:
|
||||
public function testIdentityMapReference(): void
|
||||
{
|
||||
$objectA = $this->entityManager->getReference('EntityName', 1);
|
||||
// check for proxyinterface
|
||||
$this->assertInstanceOf('Doctrine\Persistence\Proxy', $objectA);
|
||||
// check entity is not initialized
|
||||
$this->assertTrue($this->entityManager->isUninitializedObject($objectA));
|
||||
|
||||
$objectB = $this->entityManager->find('EntityName', 1);
|
||||
|
||||
|
||||
@@ -718,6 +718,7 @@ methods:
|
||||
|
||||
* ``andX($arg1, $arg2, ...)``
|
||||
* ``orX($arg1, $arg2, ...)``
|
||||
* ``not($expression)``
|
||||
* ``eq($field, $value)``
|
||||
* ``gt($field, $value)``
|
||||
* ``lt($field, $value)``
|
||||
|
||||
@@ -286,17 +286,53 @@ as follows:
|
||||
After an entity has been removed, its in-memory state is the same as
|
||||
before the removal, except for generated identifiers.
|
||||
|
||||
Removing an entity will also automatically delete any existing
|
||||
records in many-to-many join tables that link this entity. The
|
||||
action taken depends on the value of the ``@joinColumn`` mapping
|
||||
attribute "onDelete". Either Doctrine issues a dedicated ``DELETE``
|
||||
statement for records of each join table or it depends on the
|
||||
foreign key semantics of onDelete="CASCADE".
|
||||
During the ``EntityManager#flush()`` operation, the removed entity
|
||||
will also be removed from all collections in entities currently
|
||||
loaded into memory.
|
||||
|
||||
.. _remove_object_many_to_many_join_tables:
|
||||
|
||||
Join-table management when removing from many-to-many collections
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Regarding existing rows in many-to-many join tables that refer to
|
||||
an entity being removed, the following applies.
|
||||
|
||||
When the entity being removed does not declare the many-to-many association
|
||||
itself (that is, the many-to-many association is unidirectional and
|
||||
the entity is on the inverse side), the ORM has no reasonable way to
|
||||
detect associations targeting the entity's class. Thus, no ORM-level handling
|
||||
of join-table rows is attempted and database-level constraints apply.
|
||||
In case of database-level ``ON DELETE RESTRICT`` constraints, the
|
||||
``EntityManager#flush()`` operation may abort and a ``ConstraintViolationException``
|
||||
may be thrown. No in-memory collections will be modified in this case.
|
||||
With ``ON DELETE CASCADE``, the RDBMS will take care of removing rows
|
||||
from join tables.
|
||||
|
||||
When the entity being removed is part of bi-directional many-to-many
|
||||
association, either as the owning or inverse side, the ORM will
|
||||
delete rows from join tables before removing the entity itself. That means
|
||||
database-level ``ON DELETE RESTRICT`` constraints on join tables are not
|
||||
effective, since the join table rows are removed first. Removal of join table
|
||||
rows happens through specialized methods in entity and collection persister
|
||||
classes and take one query per entity and join table. In case the association
|
||||
uses a ``@JoinColumn`` configuration with ``onDelete="CASCADE"``, instead
|
||||
of using a dedicated ``DELETE`` query the database-level operation will be
|
||||
relied upon.
|
||||
|
||||
.. note::
|
||||
|
||||
In case you rely on database-level ``ON DELETE RESTRICT`` constraints,
|
||||
be aware that by making many-to-many associations bidirectional the
|
||||
assumed protection may be lost.
|
||||
|
||||
|
||||
Performance of different deletion strategies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Deleting an object with all its associated objects can be achieved
|
||||
in multiple ways with very different performance impacts.
|
||||
|
||||
|
||||
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM
|
||||
will fetch this association. If its a Single association it will
|
||||
pass this entity to
|
||||
|
||||
@@ -16,9 +16,9 @@ setup for the latest code in trunk.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
...
|
||||
@@ -102,9 +102,9 @@ of several common elements:
|
||||
|
||||
// Doctrine.Tests.ORM.Mapping.User.dcm.xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\ORM\Mapping\User" table="cms_users">
|
||||
@@ -769,9 +769,9 @@ entity relationship. You can define this in XML with the "association-key" attri
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Application\Model\ArticleAttribute">
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
Welcome to Doctrine 2 ORM's documentation!
|
||||
==========================================
|
||||
|
||||
Tutorials
|
||||
---------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
tutorials/getting-started
|
||||
tutorials/getting-started-database
|
||||
tutorials/getting-started-models
|
||||
tutorials/working-with-indexed-associations
|
||||
tutorials/extra-lazy-associations
|
||||
tutorials/composite-primary-keys
|
||||
tutorials/ordered-associations
|
||||
tutorials/override-field-association-mappings-in-subclasses
|
||||
tutorials/pagination.rst
|
||||
tutorials/embeddables.rst
|
||||
|
||||
Reference Guide
|
||||
---------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:numbered:
|
||||
|
||||
reference/architecture
|
||||
reference/configuration.rst
|
||||
reference/faq
|
||||
reference/basic-mapping
|
||||
reference/association-mapping
|
||||
reference/inheritance-mapping
|
||||
reference/working-with-objects
|
||||
reference/working-with-associations
|
||||
reference/events
|
||||
reference/unitofwork
|
||||
reference/unitofwork-associations
|
||||
reference/transactions-and-concurrency
|
||||
reference/batch-processing
|
||||
reference/dql-doctrine-query-language
|
||||
reference/query-builder
|
||||
reference/native-sql
|
||||
reference/change-tracking-policies
|
||||
reference/partial-objects
|
||||
reference/annotations-reference
|
||||
reference/attributes-reference
|
||||
reference/xml-mapping
|
||||
reference/yaml-mapping
|
||||
reference/php-mapping
|
||||
reference/caching
|
||||
reference/improving-performance
|
||||
reference/tools
|
||||
reference/metadata-drivers
|
||||
reference/best-practices
|
||||
reference/limitations-and-known-issues
|
||||
tutorials/pagination
|
||||
reference/filters
|
||||
reference/namingstrategy
|
||||
reference/advanced-configuration
|
||||
reference/second-level-cache
|
||||
reference/security
|
||||
|
||||
|
||||
Cookbook
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
cookbook/aggregate-fields
|
||||
cookbook/custom-mapping-types
|
||||
cookbook/decorator-pattern
|
||||
cookbook/dql-custom-walkers
|
||||
cookbook/dql-user-defined-functions
|
||||
cookbook/implementing-arrayaccess-for-domain-objects
|
||||
cookbook/implementing-the-notify-changetracking-policy
|
||||
cookbook/resolve-target-entity-listener
|
||||
cookbook/sql-table-prefixes
|
||||
cookbook/strategy-cookbook-introduction
|
||||
cookbook/validation-of-entities
|
||||
cookbook/working-with-datetime
|
||||
cookbook/mysql-enums
|
||||
cookbook/advanced-field-value-conversion-using-custom-mapping-types
|
||||
cookbook/entities-in-session
|
||||
|
||||
@@ -85,9 +85,9 @@ and year of production as primary keys:
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="VehicleCatalogue\Model\Car">
|
||||
@@ -267,9 +267,9 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Application\Model\ArticleAttribute">
|
||||
|
||||
@@ -85,9 +85,9 @@ switch to extra lazy as shown in these examples:
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\CMS\CmsGroup">
|
||||
|
||||
@@ -22,5 +22,5 @@ In this workflow you would modify the database schema first and then
|
||||
regenerate the PHP code to use with this schema. You need a flexible
|
||||
code-generator for this task.
|
||||
|
||||
We spinned off a subproject, Doctrine CodeGenerator, that will fill this gap and
|
||||
We spun off a subproject, Doctrine CodeGenerator, that will fill this gap and
|
||||
allow you to do *Database First* development.
|
||||
|
||||
@@ -102,8 +102,7 @@ Install Doctrine using the Composer Dependency Management tool, by calling:
|
||||
This will install the packages Doctrine Common, Doctrine DBAL, Doctrine ORM,
|
||||
into the ``vendor`` directory.
|
||||
|
||||
Add the following directories:
|
||||
::
|
||||
Add the following directories::
|
||||
|
||||
doctrine2-tutorial
|
||||
|-- config
|
||||
@@ -322,7 +321,7 @@ data in your storage, and later in your application when the data is loaded agai
|
||||
.. note::
|
||||
|
||||
This method, although very common, is inappropriate for Domain Driven
|
||||
Design (`DDD <https://en.wikipedia.org/wiki/Domain-driven_design>`)
|
||||
Design (`DDD <https://en.wikipedia.org/wiki/Domain-driven_design>`_)
|
||||
where methods should represent real business operations and not simple
|
||||
property change, And business invariants should be maintained both in the
|
||||
application state (entities in this case) and in the database, with no
|
||||
@@ -449,7 +448,7 @@ entity.
|
||||
|
||||
.. note::
|
||||
|
||||
A `DTO <https://en.wikipedia.org/wiki/Data_transfer_object>` is an object
|
||||
A `DTO <https://en.wikipedia.org/wiki/Data_transfer_object>`_ is an object
|
||||
that only carries data without any logic. Its only goal is to be transferred
|
||||
from one service to another.
|
||||
A ``DTO`` often represents data sent by a client and that has to be validated,
|
||||
@@ -558,10 +557,10 @@ methods, but you only need to choose one.
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/Product.dcm.xml -->
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Product" table="products">
|
||||
<id name="id" type="integer">
|
||||
@@ -1139,10 +1138,10 @@ the ``Product`` before:
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/Bug.dcm.xml -->
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Bug" table="bugs">
|
||||
<id name="id" type="integer">
|
||||
@@ -1294,10 +1293,10 @@ Finally, we'll add metadata mappings for the ``User`` entity.
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- config/xml/User.dcm.xml -->
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="User" table="users">
|
||||
<id name="id" type="integer">
|
||||
@@ -1344,8 +1343,7 @@ means the join details have already been defined on the owning
|
||||
side. Therefore we only have to specify the property on the Bug
|
||||
class that holds the owning sides.
|
||||
|
||||
Update your database schema by running:
|
||||
::
|
||||
Update your database schema by running::
|
||||
|
||||
$ php bin/doctrine orm:schema-tool:update --force
|
||||
|
||||
@@ -1819,9 +1817,9 @@ we have to adjust the metadata slightly.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Bug" table="bugs" repository-class="BugRepository">
|
||||
|
||||
@@ -161,9 +161,9 @@ The code and mappings for the Market entity looks like this:
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\StockExchange\Market">
|
||||
@@ -278,9 +278,9 @@ here are the code and mappings for it:
|
||||
.. code-block:: xml
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||
|
||||
<entity name="Doctrine\Tests\Models\StockExchange\Stock">
|
||||
|
||||
@@ -302,7 +302,7 @@
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
|
||||
<xs:attribute name="type" type="orm:type" default="string" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="unique" type="xs:boolean" default="false" />
|
||||
@@ -330,6 +330,7 @@
|
||||
|
||||
<xs:complexType name="discriminator-column">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
@@ -414,7 +415,7 @@
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="type" type="orm:type" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="association-key" type="xs:boolean" default="false" />
|
||||
@@ -446,6 +447,13 @@
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="type" id="type">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:pattern value="([a-zA-Z_u01-uff][a-zA-Z0-9_u01-uff]+)|(\c+)" id="type.class.pattern">
|
||||
</xs:pattern>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="inverse-join-columns">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />
|
||||
@@ -630,7 +638,7 @@
|
||||
<xs:element name="options" type="orm:options" minOccurs="0" />
|
||||
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
|
||||
<xs:attribute name="type" type="orm:type" default="string" />
|
||||
<xs:attribute name="column" type="orm:columntoken" />
|
||||
<xs:attribute name="length" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="unique" type="xs:boolean" default="false" />
|
||||
|
||||
@@ -1010,7 +1010,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* Alias for getSingleResult(HYDRATE_SINGLE_SCALAR).
|
||||
*
|
||||
* @return mixed The scalar result.
|
||||
* @return bool|float|int|string The scalar result.
|
||||
*
|
||||
* @throws NoResultException If the query returned no result.
|
||||
* @throws NonUniqueResultException If the query result is not unique.
|
||||
|
||||
@@ -14,6 +14,8 @@ use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
|
||||
/**
|
||||
* Contract for building second level cache regions components.
|
||||
*
|
||||
* @psalm-import-type AssociationMapping from ClassMetadata
|
||||
*/
|
||||
interface CacheFactory
|
||||
{
|
||||
@@ -31,7 +33,7 @@ interface CacheFactory
|
||||
/**
|
||||
* Build a collection persister for the given relation mapping.
|
||||
*
|
||||
* @param mixed[] $mapping The association mapping.
|
||||
* @param AssociationMapping $mapping The association mapping.
|
||||
*
|
||||
* @return CachedCollectionPersister
|
||||
*/
|
||||
|
||||
@@ -48,7 +48,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getEntityCacheRegion($className)
|
||||
{
|
||||
@@ -63,7 +63,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getCollectionCacheRegion($className, $association)
|
||||
{
|
||||
@@ -78,7 +78,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function containsEntity($className, $identifier)
|
||||
{
|
||||
@@ -93,7 +93,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictEntity($className, $identifier)
|
||||
{
|
||||
@@ -108,7 +108,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictEntityRegion($className)
|
||||
{
|
||||
@@ -123,7 +123,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictEntityRegions()
|
||||
{
|
||||
@@ -141,7 +141,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function containsCollection($className, $association, $ownerIdentifier)
|
||||
{
|
||||
@@ -156,7 +156,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictCollection($className, $association, $ownerIdentifier)
|
||||
{
|
||||
@@ -171,7 +171,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictCollectionRegion($className, $association)
|
||||
{
|
||||
@@ -186,7 +186,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictCollectionRegions()
|
||||
{
|
||||
@@ -210,7 +210,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function containsQuery($regionName)
|
||||
{
|
||||
@@ -218,7 +218,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictQueryRegion($regionName = null)
|
||||
{
|
||||
@@ -234,7 +234,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictQueryRegions()
|
||||
{
|
||||
@@ -246,7 +246,7 @@ class DefaultCache implements Cache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getQueryCache($regionName = null)
|
||||
{
|
||||
|
||||
@@ -106,7 +106,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata)
|
||||
{
|
||||
@@ -134,10 +134,11 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildCachedCollectionPersister(EntityManagerInterface $em, CollectionPersister $persister, array $mapping)
|
||||
{
|
||||
assert(isset($mapping['cache']));
|
||||
$usage = $mapping['cache']['usage'];
|
||||
$region = $this->getRegion($mapping['cache']);
|
||||
|
||||
@@ -161,7 +162,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildQueryCache(EntityManagerInterface $em, $regionName = null)
|
||||
{
|
||||
@@ -177,7 +178,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildCollectionHydrator(EntityManagerInterface $em, array $mapping)
|
||||
{
|
||||
@@ -185,7 +186,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata)
|
||||
{
|
||||
@@ -193,7 +194,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getRegion(array $cache)
|
||||
{
|
||||
@@ -224,7 +225,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getTimestampRegion()
|
||||
{
|
||||
@@ -239,7 +240,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createCache(EntityManagerInterface $entityManager)
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, $collection)
|
||||
{
|
||||
@@ -49,7 +49,7 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection)
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, $entity)
|
||||
{
|
||||
@@ -140,7 +140,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, EntityCacheEntry $entry, $entity = null)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,6 @@ use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\Persistence\Proxy;
|
||||
|
||||
use function array_map;
|
||||
use function array_shift;
|
||||
@@ -29,6 +28,8 @@ use function reset;
|
||||
|
||||
/**
|
||||
* Default query cache implementation.
|
||||
*
|
||||
* @psalm-import-type AssociationMapping from ClassMetadata
|
||||
*/
|
||||
class DefaultQueryCache implements QueryCache
|
||||
{
|
||||
@@ -66,7 +67,7 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = [])
|
||||
{
|
||||
@@ -225,7 +226,7 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function put(QueryCacheKey $key, ResultSetMapping $rsm, $result, array $hints = [])
|
||||
{
|
||||
@@ -326,8 +327,8 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $assoc
|
||||
* @param mixed $assocValue
|
||||
* @param AssociationMapping $assoc
|
||||
* @param mixed $assocValue
|
||||
*
|
||||
* @return mixed[]|null
|
||||
* @psalm-return array{targetEntity: class-string, type: mixed, list?: array[], identifier?: array}|null
|
||||
@@ -343,7 +344,7 @@ class DefaultQueryCache implements QueryCache
|
||||
$assocIdentifier = $this->uow->getEntityIdentifier($assocValue);
|
||||
$entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier);
|
||||
|
||||
if (! $assocValue instanceof Proxy && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
|
||||
if (! $this->uow->isUninitializedObject($assocValue) && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
|
||||
// Entity put fail
|
||||
if (! $assocPersister->storeEntityCache($assocValue, $entityKey)) {
|
||||
return null;
|
||||
@@ -448,7 +449,7 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
@@ -456,7 +457,7 @@ class DefaultQueryCache implements QueryCache
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getRegion()
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCacheHit($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -50,7 +50,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCacheMiss($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -60,7 +60,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCachePut($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -70,7 +70,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCacheHit($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -80,7 +80,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCacheMiss($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -90,7 +90,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCachePut($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -100,7 +100,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCacheHit($regionName, QueryCacheKey $key)
|
||||
{
|
||||
@@ -110,7 +110,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCacheMiss($regionName, QueryCacheKey $key)
|
||||
{
|
||||
@@ -120,7 +120,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCachePut($regionName, QueryCacheKey $key)
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
private $cachePutCountMap = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCacheMiss($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -34,7 +34,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCacheHit($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -43,7 +43,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function collectionCachePut($regionName, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -52,7 +52,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCacheMiss($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -61,7 +61,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCacheHit($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -70,7 +70,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function entityCachePut($regionName, EntityCacheKey $key)
|
||||
{
|
||||
@@ -79,7 +79,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCacheHit($regionName, QueryCacheKey $key)
|
||||
{
|
||||
@@ -88,7 +88,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCacheMiss($regionName, QueryCacheKey $key)
|
||||
{
|
||||
@@ -97,7 +97,7 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function queryCachePut($regionName, QueryCacheKey $key)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@ use function array_values;
|
||||
use function assert;
|
||||
use function count;
|
||||
|
||||
/** @psalm-import-type AssociationMapping from ClassMetadata */
|
||||
abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
{
|
||||
/** @var UnitOfWork */
|
||||
@@ -64,7 +65,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
* @param CollectionPersister $persister The collection persister that will be cached.
|
||||
* @param Region $region The collection region.
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
* @param mixed[] $association The association mapping.
|
||||
* @param AssociationMapping $association The association mapping.
|
||||
*/
|
||||
public function __construct(CollectionPersister $persister, Region $region, EntityManagerInterface $em, array $association)
|
||||
{
|
||||
@@ -85,7 +86,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getCacheRegion()
|
||||
{
|
||||
@@ -93,7 +94,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSourceEntityMetadata()
|
||||
{
|
||||
@@ -101,7 +102,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getTargetEntityMetadata()
|
||||
{
|
||||
@@ -109,7 +110,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key)
|
||||
{
|
||||
@@ -123,7 +124,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function storeCollectionCache(CollectionCacheKey $key, $elements)
|
||||
{
|
||||
@@ -167,7 +168,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function contains(PersistentCollection $collection, $element)
|
||||
{
|
||||
@@ -175,7 +176,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function containsKey(PersistentCollection $collection, $key)
|
||||
{
|
||||
@@ -183,7 +184,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function count(PersistentCollection $collection)
|
||||
{
|
||||
@@ -199,7 +200,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get(PersistentCollection $collection, $index)
|
||||
{
|
||||
@@ -207,7 +208,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function slice(PersistentCollection $collection, $offset, $length = null)
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ use function spl_object_id;
|
||||
class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionComplete()
|
||||
{
|
||||
@@ -32,7 +32,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionRolledBack()
|
||||
{
|
||||
@@ -40,7 +40,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete(PersistentCollection $collection)
|
||||
{
|
||||
@@ -53,7 +53,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update(PersistentCollection $collection)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ use Doctrine\ORM\PersistentCollection;
|
||||
class ReadOnlyCachedCollectionPersister extends NonStrictReadWriteCachedCollectionPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update(PersistentCollection $collection)
|
||||
{
|
||||
|
||||
@@ -7,21 +7,23 @@ namespace Doctrine\ORM\Cache\Persister\Collection;
|
||||
use Doctrine\ORM\Cache\CollectionCacheKey;
|
||||
use Doctrine\ORM\Cache\ConcurrentRegion;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
|
||||
use function spl_object_id;
|
||||
|
||||
/** @psalm-import-type AssociationMapping from ClassMetadata */
|
||||
class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
{
|
||||
/** @param mixed[] $association The association mapping. */
|
||||
/** @param AssociationMapping $association The association mapping. */
|
||||
public function __construct(CollectionPersister $persister, ConcurrentRegion $region, EntityManagerInterface $em, array $association)
|
||||
{
|
||||
parent::__construct($persister, $region, $em, $association);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionComplete()
|
||||
{
|
||||
@@ -41,7 +43,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionRolledBack()
|
||||
{
|
||||
@@ -61,7 +63,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete(PersistentCollection $collection)
|
||||
{
|
||||
@@ -82,7 +84,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update(PersistentCollection $collection)
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
|
||||
use function array_merge;
|
||||
use function assert;
|
||||
use function serialize;
|
||||
use function sha1;
|
||||
@@ -98,7 +99,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function addInsert($entity)
|
||||
{
|
||||
@@ -106,7 +107,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getInserts()
|
||||
{
|
||||
@@ -114,7 +115,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, ?array $orderBy = null)
|
||||
{
|
||||
@@ -130,7 +131,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getInsertSQL()
|
||||
{
|
||||
@@ -138,7 +139,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getResultSetMapping()
|
||||
{
|
||||
@@ -146,7 +147,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSelectConditionStatementSQL($field, $value, $assoc = null, $comparison = null)
|
||||
{
|
||||
@@ -154,7 +155,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function exists($entity, ?Criteria $extraConditions = null)
|
||||
{
|
||||
@@ -170,7 +171,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getCacheRegion()
|
||||
{
|
||||
@@ -184,7 +185,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function storeEntityCache($entity, EntityCacheKey $key)
|
||||
{
|
||||
@@ -262,7 +263,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function expandParameters($criteria)
|
||||
{
|
||||
@@ -270,7 +271,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function expandCriteriaParameters(Criteria $criteria)
|
||||
{
|
||||
@@ -278,7 +279,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassMetadata()
|
||||
{
|
||||
@@ -286,7 +287,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getManyToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||
{
|
||||
@@ -294,7 +295,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getOneToManyCollection(array $assoc, $sourceEntity, $offset = null, $limit = null)
|
||||
{
|
||||
@@ -302,7 +303,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getOwningTable($fieldName)
|
||||
{
|
||||
@@ -310,17 +311,23 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function executeInserts()
|
||||
{
|
||||
$this->queuedCache['insert'] = $this->persister->getInserts();
|
||||
// The commit order/foreign key relationships may make it necessary that multiple calls to executeInsert()
|
||||
// are performed, so collect all the new entities.
|
||||
$newInserts = $this->persister->getInserts();
|
||||
|
||||
if ($newInserts) {
|
||||
$this->queuedCache['insert'] = array_merge($this->queuedCache['insert'] ?? [], $newInserts);
|
||||
}
|
||||
|
||||
return $this->persister->executeInserts();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function load(array $criteria, $entity = null, $assoc = null, array $hints = [], $lockMode = null, $limit = null, ?array $orderBy = null)
|
||||
{
|
||||
@@ -364,7 +371,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadAll(array $criteria = [], ?array $orderBy = null, $limit = null, $offset = null)
|
||||
{
|
||||
@@ -400,7 +407,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadById(array $identifier, $entity = null)
|
||||
{
|
||||
@@ -464,7 +471,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadCriteria(Criteria $criteria)
|
||||
{
|
||||
@@ -503,7 +510,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
|
||||
{
|
||||
@@ -538,7 +545,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
|
||||
{
|
||||
@@ -573,7 +580,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function loadOneToOneEntity(array $assoc, $sourceEntity, array $identifier = [])
|
||||
{
|
||||
@@ -581,7 +588,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function lock(array $criteria, $lockMode)
|
||||
{
|
||||
@@ -589,7 +596,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function refresh(array $id, $entity, $lockMode = null)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ use function get_class;
|
||||
class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionComplete()
|
||||
{
|
||||
@@ -48,7 +48,7 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionRolledBack()
|
||||
{
|
||||
@@ -56,7 +56,7 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($entity)
|
||||
{
|
||||
@@ -73,7 +73,7 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($entity)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyEntity;
|
||||
class ReadOnlyCachedEntityPersister extends NonStrictReadWriteCachedEntityPersister
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($entity)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionComplete()
|
||||
{
|
||||
@@ -51,7 +51,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function afterTransactionRolledBack()
|
||||
{
|
||||
@@ -71,7 +71,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function delete($entity)
|
||||
{
|
||||
@@ -96,7 +96,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update($entity)
|
||||
{
|
||||
|
||||
@@ -91,7 +91,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
@@ -109,7 +109,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function contains(CacheKey $key)
|
||||
{
|
||||
@@ -117,7 +117,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get(CacheKey $key)
|
||||
{
|
||||
@@ -132,7 +132,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMultiple(CollectionCacheEntry $collection)
|
||||
{
|
||||
@@ -164,7 +164,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -182,7 +182,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -192,7 +192,7 @@ class DefaultRegion implements Region
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -116,7 +116,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
@@ -124,7 +124,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function contains(CacheKey $key)
|
||||
{
|
||||
@@ -136,7 +136,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get(CacheKey $key)
|
||||
{
|
||||
@@ -148,7 +148,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getMultiple(CollectionCacheEntry $collection)
|
||||
{
|
||||
@@ -160,7 +160,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function put(CacheKey $key, CacheEntry $entry, ?Lock $lock = null)
|
||||
{
|
||||
@@ -172,7 +172,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evict(CacheKey $key)
|
||||
{
|
||||
@@ -184,7 +184,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function evictAll()
|
||||
{
|
||||
@@ -202,7 +202,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function lock(CacheKey $key)
|
||||
{
|
||||
@@ -223,7 +223,7 @@ class FileLockRegion implements ConcurrentRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function unlock(CacheKey $key, Lock $lock)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ use Doctrine\ORM\Cache\TimestampRegion;
|
||||
class UpdateTimestampCache extends DefaultRegion implements TimestampRegion
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function update(CacheKey $key)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ class TimestampQueryCacheValidator implements QueryCacheValidator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isValid(QueryCacheKey $key, QueryCacheEntry $entry)
|
||||
{
|
||||
|
||||
@@ -62,8 +62,6 @@ use function trim;
|
||||
* It combines all configuration options from DBAL & ORM.
|
||||
*
|
||||
* Internal note: When adding a new configuration option just write a getter/setter pair.
|
||||
*
|
||||
* @psalm-import-type AutogenerateMode from ProxyFactory
|
||||
*/
|
||||
class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
@@ -95,8 +93,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Gets the strategy for automatically generating proxy classes.
|
||||
*
|
||||
* @return int Possible values are constants of Doctrine\ORM\Proxy\ProxyFactory.
|
||||
* @psalm-return AutogenerateMode
|
||||
* @return ProxyFactory::AUTOGENERATE_*
|
||||
*/
|
||||
public function getAutoGenerateProxyClasses()
|
||||
{
|
||||
@@ -106,9 +103,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets the strategy for automatically generating proxy classes.
|
||||
*
|
||||
* @param bool|int $autoGenerate Possible values are constants of Doctrine\ORM\Proxy\ProxyFactory.
|
||||
* @psalm-param bool|AutogenerateMode $autoGenerate
|
||||
* True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
|
||||
* @param bool|ProxyFactory::AUTOGENERATE_* $autoGenerate True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -164,7 +159,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @return AnnotationDriver
|
||||
*/
|
||||
public function newDefaultAnnotationDriver($paths = [], $useSimpleAnnotationReader = true)
|
||||
public function newDefaultAnnotationDriver($paths = [], $useSimpleAnnotationReader = true, bool $reportFieldsWhereDeclared = false)
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -203,15 +198,16 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
|
||||
return new AnnotationDriver(
|
||||
$reader,
|
||||
(array) $paths
|
||||
(array) $paths,
|
||||
$reportFieldsWhereDeclared
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated No replacement planned.
|
||||
*
|
||||
* Adds a namespace under a certain alias.
|
||||
*
|
||||
* @deprecated No replacement planned.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param string $namespace
|
||||
*
|
||||
|
||||
@@ -31,7 +31,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
@@ -39,7 +39,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getExpressionBuilder()
|
||||
{
|
||||
@@ -47,7 +47,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
*
|
||||
@@ -61,7 +61,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassMetadata($className)
|
||||
{
|
||||
@@ -69,7 +69,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function beginTransaction()
|
||||
{
|
||||
@@ -77,7 +77,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function transactional($func)
|
||||
{
|
||||
@@ -85,7 +85,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function wrapInTransaction(callable $func)
|
||||
{
|
||||
@@ -102,7 +102,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
@@ -110,7 +110,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
@@ -118,7 +118,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createQuery($dql = '')
|
||||
{
|
||||
@@ -126,7 +126,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createNamedQuery($name)
|
||||
{
|
||||
@@ -134,7 +134,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createNativeQuery($sql, ResultSetMapping $rsm)
|
||||
{
|
||||
@@ -142,7 +142,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createNamedNativeQuery($name)
|
||||
{
|
||||
@@ -150,7 +150,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function createQueryBuilder()
|
||||
{
|
||||
@@ -158,7 +158,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReference($entityName, $id)
|
||||
{
|
||||
@@ -166,7 +166,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPartialReference($entityName, $identifier)
|
||||
{
|
||||
@@ -174,7 +174,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
@@ -182,7 +182,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function copy($entity, $deep = false)
|
||||
{
|
||||
@@ -190,7 +190,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function lock($entity, $lockMode, $lockVersion = null)
|
||||
{
|
||||
@@ -198,7 +198,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function find($className, $id, $lockMode = null, $lockVersion = null)
|
||||
{
|
||||
@@ -206,7 +206,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function flush($entity = null)
|
||||
{
|
||||
@@ -214,7 +214,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function refresh($object)
|
||||
{
|
||||
@@ -228,7 +228,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getEventManager()
|
||||
{
|
||||
@@ -236,7 +236,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getConfiguration()
|
||||
{
|
||||
@@ -244,7 +244,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isOpen()
|
||||
{
|
||||
@@ -252,7 +252,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getUnitOfWork()
|
||||
{
|
||||
@@ -260,7 +260,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getHydrator($hydrationMode)
|
||||
{
|
||||
@@ -268,7 +268,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function newHydrator($hydrationMode)
|
||||
{
|
||||
@@ -276,7 +276,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getProxyFactory()
|
||||
{
|
||||
@@ -284,7 +284,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
@@ -292,7 +292,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isFiltersStateClean()
|
||||
{
|
||||
@@ -300,7 +300,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function hasFilters()
|
||||
{
|
||||
@@ -308,7 +308,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getCache()
|
||||
{
|
||||
|
||||
@@ -953,6 +953,14 @@ class EntityManager implements EntityManagerInterface
|
||||
$this->unitOfWork->initializeObject($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isUninitializedObject($obj): bool
|
||||
{
|
||||
return $this->unitOfWork->isUninitializedObject($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create EntityManager instances.
|
||||
*
|
||||
|
||||
@@ -27,7 +27,7 @@ use Doctrine\Persistence\ObjectManager;
|
||||
interface EntityManagerInterface extends ObjectManager
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
*
|
||||
|
||||
@@ -297,7 +297,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getClassName()
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ class AssignedGenerator extends AbstractIdGenerator
|
||||
/**
|
||||
* Returns the identifier assigned to the given entity.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws EntityMissingAssignedId
|
||||
*/
|
||||
|
||||
@@ -49,7 +49,7 @@ class IdentityGenerator extends AbstractIdGenerator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isPostInsertGenerator()
|
||||
{
|
||||
|
||||
@@ -21,20 +21,20 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_allocationSize;
|
||||
private $allocationSize;
|
||||
|
||||
/**
|
||||
* The name of the sequence.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_sequenceName;
|
||||
private $sequenceName;
|
||||
|
||||
/** @var int */
|
||||
private $_nextValue = 0;
|
||||
private $nextValue = 0;
|
||||
|
||||
/** @var int|null */
|
||||
private $_maxValue = null;
|
||||
private $maxValue = null;
|
||||
|
||||
/**
|
||||
* Initializes a new sequence generator.
|
||||
@@ -44,8 +44,8 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*/
|
||||
public function __construct($sequenceName, $allocationSize)
|
||||
{
|
||||
$this->_sequenceName = $sequenceName;
|
||||
$this->_allocationSize = $allocationSize;
|
||||
$this->sequenceName = $sequenceName;
|
||||
$this->allocationSize = $allocationSize;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,20 +53,20 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*/
|
||||
public function generateId(EntityManagerInterface $em, $entity)
|
||||
{
|
||||
if ($this->_maxValue === null || $this->_nextValue === $this->_maxValue) {
|
||||
if ($this->maxValue === null || $this->nextValue === $this->maxValue) {
|
||||
// Allocate new values
|
||||
$connection = $em->getConnection();
|
||||
$sql = $connection->getDatabasePlatform()->getSequenceNextValSQL($this->_sequenceName);
|
||||
$sql = $connection->getDatabasePlatform()->getSequenceNextValSQL($this->sequenceName);
|
||||
|
||||
if ($connection instanceof PrimaryReadReplicaConnection) {
|
||||
$connection->ensureConnectedToPrimary();
|
||||
}
|
||||
|
||||
$this->_nextValue = (int) $connection->fetchOne($sql);
|
||||
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
|
||||
$this->nextValue = (int) $connection->fetchOne($sql);
|
||||
$this->maxValue = $this->nextValue + $this->allocationSize;
|
||||
}
|
||||
|
||||
return $this->_nextValue++;
|
||||
return $this->nextValue++;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +76,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*/
|
||||
public function getCurrentMaxValue()
|
||||
{
|
||||
return $this->_maxValue;
|
||||
return $this->maxValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,7 +86,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
*/
|
||||
public function getNextValue()
|
||||
{
|
||||
return $this->_nextValue;
|
||||
return $this->nextValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,8 +103,8 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [
|
||||
'allocationSize' => $this->_allocationSize,
|
||||
'sequenceName' => $this->_sequenceName,
|
||||
'allocationSize' => $this->allocationSize,
|
||||
'sequenceName' => $this->sequenceName,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
/** @param array<string, mixed> $data */
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
$this->_sequenceName = $data['sequenceName'];
|
||||
$this->_allocationSize = $data['allocationSize'];
|
||||
$this->sequenceName = $data['sequenceName'];
|
||||
$this->allocationSize = $data['allocationSize'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,19 +14,19 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
class TableGenerator extends AbstractIdGenerator
|
||||
{
|
||||
/** @var string */
|
||||
private $_tableName;
|
||||
private $tableName;
|
||||
|
||||
/** @var string */
|
||||
private $_sequenceName;
|
||||
private $sequenceName;
|
||||
|
||||
/** @var int */
|
||||
private $_allocationSize;
|
||||
private $allocationSize;
|
||||
|
||||
/** @var int|null */
|
||||
private $_nextValue;
|
||||
private $nextValue;
|
||||
|
||||
/** @var int|null */
|
||||
private $_maxValue;
|
||||
private $maxValue;
|
||||
|
||||
/**
|
||||
* @param string $tableName
|
||||
@@ -35,9 +35,9 @@ class TableGenerator extends AbstractIdGenerator
|
||||
*/
|
||||
public function __construct($tableName, $sequenceName = 'default', $allocationSize = 10)
|
||||
{
|
||||
$this->_tableName = $tableName;
|
||||
$this->_sequenceName = $sequenceName;
|
||||
$this->_allocationSize = $allocationSize;
|
||||
$this->tableName = $tableName;
|
||||
$this->sequenceName = $sequenceName;
|
||||
$this->allocationSize = $allocationSize;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,23 +47,23 @@ class TableGenerator extends AbstractIdGenerator
|
||||
EntityManagerInterface $em,
|
||||
$entity
|
||||
) {
|
||||
if ($this->_maxValue === null || $this->_nextValue === $this->_maxValue) {
|
||||
if ($this->maxValue === null || $this->nextValue === $this->maxValue) {
|
||||
// Allocate new values
|
||||
$conn = $em->getConnection();
|
||||
|
||||
if ($conn->getTransactionNestingLevel() === 0) {
|
||||
// use select for update
|
||||
$sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName);
|
||||
$sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->tableName, $this->sequenceName);
|
||||
$currentLevel = $conn->fetchOne($sql);
|
||||
|
||||
if ($currentLevel !== null) {
|
||||
$this->_nextValue = $currentLevel;
|
||||
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
|
||||
$this->nextValue = $currentLevel;
|
||||
$this->maxValue = $this->nextValue + $this->allocationSize;
|
||||
|
||||
$updateSql = $conn->getDatabasePlatform()->getTableHiLoUpdateNextValSql(
|
||||
$this->_tableName,
|
||||
$this->_sequenceName,
|
||||
$this->_allocationSize
|
||||
$this->tableName,
|
||||
$this->sequenceName,
|
||||
$this->allocationSize
|
||||
);
|
||||
|
||||
if ($conn->executeStatement($updateSql, [1 => $currentLevel, 2 => $currentLevel + 1]) !== 1) {
|
||||
@@ -78,6 +78,6 @@ class TableGenerator extends AbstractIdGenerator
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_nextValue++;
|
||||
return $this->nextValue++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\CommitOrder;
|
||||
|
||||
/** @internal */
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
final class Edge
|
||||
{
|
||||
/**
|
||||
@@ -27,6 +32,13 @@ final class Edge
|
||||
|
||||
public function __construct(string $from, string $to, int $weight)
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10547',
|
||||
'The %s class is deprecated and will be removed in ORM 3.0',
|
||||
self::class
|
||||
);
|
||||
|
||||
$this->from = $from;
|
||||
$this->to = $to;
|
||||
$this->weight = $weight;
|
||||
|
||||
@@ -4,9 +4,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\CommitOrder;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
/** @internal */
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
final class Vertex
|
||||
{
|
||||
/**
|
||||
@@ -32,6 +36,13 @@ final class Vertex
|
||||
|
||||
public function __construct(string $hash, ClassMetadata $value)
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10547',
|
||||
'The %s class is deprecated and will be removed in ORM 3.0',
|
||||
self::class
|
||||
);
|
||||
|
||||
$this->hash = $hash;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\CommitOrder;
|
||||
|
||||
/** @internal */
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
final class VertexState
|
||||
{
|
||||
public const NOT_VISITED = 0;
|
||||
@@ -13,5 +18,11 @@ final class VertexState
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10547',
|
||||
'The %s class is deprecated and will be removed in ORM 3.0',
|
||||
self::class
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Internal\CommitOrder\Edge;
|
||||
use Doctrine\ORM\Internal\CommitOrder\Vertex;
|
||||
use Doctrine\ORM\Internal\CommitOrder\VertexState;
|
||||
@@ -17,6 +18,8 @@ use function array_reverse;
|
||||
* using a depth-first searching (DFS) to traverse the graph built in memory.
|
||||
* This algorithm have a linear running time based on nodes (V) and dependency
|
||||
* between the nodes (E), resulting in a computational complexity of O(V + E).
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
class CommitOrderCalculator
|
||||
{
|
||||
@@ -45,6 +48,16 @@ class CommitOrderCalculator
|
||||
*/
|
||||
private $sortedNodeList = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10547',
|
||||
'The %s class is deprecated and will be removed in ORM 3.0',
|
||||
self::class
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for node (vertex) existence in graph.
|
||||
*
|
||||
|
||||
@@ -19,39 +19,39 @@ use function reset;
|
||||
class ArrayHydrator extends AbstractHydrator
|
||||
{
|
||||
/** @var array<string,bool> */
|
||||
private $_rootAliases = [];
|
||||
private $rootAliases = [];
|
||||
|
||||
/** @var bool */
|
||||
private $_isSimpleQuery = false;
|
||||
private $isSimpleQuery = false;
|
||||
|
||||
/** @var mixed[] */
|
||||
private $_identifierMap = [];
|
||||
private $identifierMap = [];
|
||||
|
||||
/** @var mixed[] */
|
||||
private $_resultPointers = [];
|
||||
private $resultPointers = [];
|
||||
|
||||
/** @var array<string,string> */
|
||||
private $_idTemplate = [];
|
||||
private $idTemplate = [];
|
||||
|
||||
/** @var int */
|
||||
private $_resultCounter = 0;
|
||||
private $resultCounter = 0;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function prepare()
|
||||
{
|
||||
$this->_isSimpleQuery = count($this->resultSetMapping()->aliasMap) <= 1;
|
||||
$this->isSimpleQuery = count($this->resultSetMapping()->aliasMap) <= 1;
|
||||
|
||||
foreach ($this->resultSetMapping()->aliasMap as $dqlAlias => $className) {
|
||||
$this->_identifierMap[$dqlAlias] = [];
|
||||
$this->_resultPointers[$dqlAlias] = [];
|
||||
$this->_idTemplate[$dqlAlias] = '';
|
||||
$this->identifierMap[$dqlAlias] = [];
|
||||
$this->resultPointers[$dqlAlias] = [];
|
||||
$this->idTemplate[$dqlAlias] = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
@@ -65,12 +65,12 @@ class ArrayHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
// 1) Initialize
|
||||
$id = $this->_idTemplate; // initialize the id-memory
|
||||
$id = $this->idTemplate; // initialize the id-memory
|
||||
$nonemptyComponents = [];
|
||||
$rowData = $this->gatherRowData($row, $id, $nonemptyComponents);
|
||||
|
||||
@@ -91,14 +91,14 @@ class ArrayHydrator extends AbstractHydrator
|
||||
|
||||
// Get a reference to the right element in the result tree.
|
||||
// This element will get the associated element attached.
|
||||
if ($this->resultSetMapping()->isMixed && isset($this->_rootAliases[$parent])) {
|
||||
$first = reset($this->_resultPointers);
|
||||
if ($this->resultSetMapping()->isMixed && isset($this->rootAliases[$parent])) {
|
||||
$first = reset($this->resultPointers);
|
||||
// TODO: Exception if $key === null ?
|
||||
$baseElement =& $this->_resultPointers[$parent][key($first)];
|
||||
} elseif (isset($this->_resultPointers[$parent])) {
|
||||
$baseElement =& $this->_resultPointers[$parent];
|
||||
$baseElement =& $this->resultPointers[$parent][key($first)];
|
||||
} elseif (isset($this->resultPointers[$parent])) {
|
||||
$baseElement =& $this->resultPointers[$parent];
|
||||
} else {
|
||||
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
|
||||
unset($this->resultPointers[$dqlAlias]); // Ticket #1228
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -116,8 +116,8 @@ class ArrayHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
if (isset($nonemptyComponents[$dqlAlias])) {
|
||||
$indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
|
||||
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
|
||||
$indexExists = isset($this->identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
|
||||
$index = $indexExists ? $this->identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
|
||||
$indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false;
|
||||
|
||||
if (! $indexExists || ! $indexIsValid) {
|
||||
@@ -131,7 +131,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
|
||||
end($baseElement[$relationAlias]);
|
||||
|
||||
$this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = key($baseElement[$relationAlias]);
|
||||
$this->identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = key($baseElement[$relationAlias]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -155,8 +155,8 @@ class ArrayHydrator extends AbstractHydrator
|
||||
} else {
|
||||
// It's a root result element
|
||||
|
||||
$this->_rootAliases[$dqlAlias] = true; // Mark as root
|
||||
$entityKey = $this->resultSetMapping()->entityMappings[$dqlAlias] ?: 0;
|
||||
$this->rootAliases[$dqlAlias] = true; // Mark as root
|
||||
$entityKey = $this->resultSetMapping()->entityMappings[$dqlAlias] ?: 0;
|
||||
|
||||
// if this row has a NULL value for the root result id then make it a null result.
|
||||
if (! isset($nonemptyComponents[$dqlAlias])) {
|
||||
@@ -164,14 +164,14 @@ class ArrayHydrator extends AbstractHydrator
|
||||
? [$entityKey => null]
|
||||
: null;
|
||||
|
||||
$resultKey = $this->_resultCounter;
|
||||
++$this->_resultCounter;
|
||||
$resultKey = $this->resultCounter;
|
||||
++$this->resultCounter;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for an existing element
|
||||
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||
if ($this->isSimpleQuery || ! isset($this->identifierMap[$dqlAlias][$id[$dqlAlias]])) {
|
||||
$element = $this->resultSetMapping()->isMixed
|
||||
? [$entityKey => $data]
|
||||
: $data;
|
||||
@@ -180,15 +180,15 @@ class ArrayHydrator extends AbstractHydrator
|
||||
$resultKey = $row[$this->resultSetMapping()->indexByMap[$dqlAlias]];
|
||||
$result[$resultKey] = $element;
|
||||
} else {
|
||||
$resultKey = $this->_resultCounter;
|
||||
$resultKey = $this->resultCounter;
|
||||
$result[] = $element;
|
||||
|
||||
++$this->_resultCounter;
|
||||
++$this->resultCounter;
|
||||
}
|
||||
|
||||
$this->_identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
|
||||
$this->identifierMap[$dqlAlias][$id[$dqlAlias]] = $resultKey;
|
||||
} else {
|
||||
$index = $this->_identifierMap[$dqlAlias][$id[$dqlAlias]];
|
||||
$index = $this->identifierMap[$dqlAlias][$id[$dqlAlias]];
|
||||
$resultKey = $index;
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
if (! isset($resultKey)) {
|
||||
$this->_resultCounter++;
|
||||
$this->resultCounter++;
|
||||
}
|
||||
|
||||
// Append scalar values to mixed result sets
|
||||
@@ -206,7 +206,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
// this only ever happens when no object is fetched (scalar result only)
|
||||
$resultKey = isset($this->resultSetMapping()->indexByMap['scalars'])
|
||||
? $row[$this->resultSetMapping()->indexByMap['scalars']]
|
||||
: $this->_resultCounter - 1;
|
||||
: $this->resultCounter - 1;
|
||||
}
|
||||
|
||||
foreach ($rowData['scalars'] as $name => $value) {
|
||||
@@ -217,7 +217,7 @@ class ArrayHydrator extends AbstractHydrator
|
||||
// Append new object to mixed result sets
|
||||
if (isset($rowData['newObjects'])) {
|
||||
if (! isset($resultKey)) {
|
||||
$resultKey = $this->_resultCounter - 1;
|
||||
$resultKey = $this->resultCounter - 1;
|
||||
}
|
||||
|
||||
$scalarCount = (isset($rowData['scalars']) ? count($rowData['scalars']) : 0);
|
||||
@@ -253,19 +253,19 @@ class ArrayHydrator extends AbstractHydrator
|
||||
bool $oneToOne
|
||||
): void {
|
||||
if ($coll === null) {
|
||||
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
|
||||
unset($this->resultPointers[$dqlAlias]); // Ticket #1228
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($oneToOne) {
|
||||
$this->_resultPointers[$dqlAlias] =& $coll;
|
||||
$this->resultPointers[$dqlAlias] =& $coll;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($index !== false) {
|
||||
$this->_resultPointers[$dqlAlias] =& $coll[$index];
|
||||
$this->resultPointers[$dqlAlias] =& $coll[$index];
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -275,6 +275,6 @@ class ArrayHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
end($coll);
|
||||
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];
|
||||
$this->resultPointers[$dqlAlias] =& $coll[key($coll)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,21 +16,21 @@ use ReturnTypeWillChange;
|
||||
class IterableResult implements Iterator
|
||||
{
|
||||
/** @var AbstractHydrator */
|
||||
private $_hydrator;
|
||||
private $hydrator;
|
||||
|
||||
/** @var bool */
|
||||
private $_rewinded = false;
|
||||
private $rewinded = false;
|
||||
|
||||
/** @var int */
|
||||
private $_key = -1;
|
||||
private $key = -1;
|
||||
|
||||
/** @var mixed[]|null */
|
||||
private $_current = null;
|
||||
private $current = null;
|
||||
|
||||
/** @param AbstractHydrator $hydrator */
|
||||
public function __construct($hydrator)
|
||||
{
|
||||
$this->_hydrator = $hydrator;
|
||||
$this->hydrator = $hydrator;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,12 +41,12 @@ class IterableResult implements Iterator
|
||||
#[ReturnTypeWillChange]
|
||||
public function rewind()
|
||||
{
|
||||
if ($this->_rewinded === true) {
|
||||
if ($this->rewinded === true) {
|
||||
throw new HydrationException('Can only iterate a Result once.');
|
||||
}
|
||||
|
||||
$this->_current = $this->next();
|
||||
$this->_rewinded = true;
|
||||
$this->current = $this->next();
|
||||
$this->rewinded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,30 +57,30 @@ class IterableResult implements Iterator
|
||||
#[ReturnTypeWillChange]
|
||||
public function next()
|
||||
{
|
||||
$this->_current = $this->_hydrator->hydrateRow();
|
||||
$this->_key++;
|
||||
$this->current = $this->hydrator->hydrateRow();
|
||||
$this->key++;
|
||||
|
||||
return $this->_current;
|
||||
return $this->current;
|
||||
}
|
||||
|
||||
/** @return mixed */
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
{
|
||||
return $this->_current;
|
||||
return $this->current;
|
||||
}
|
||||
|
||||
/** @return int */
|
||||
#[ReturnTypeWillChange]
|
||||
public function key()
|
||||
{
|
||||
return $this->_key;
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
#[ReturnTypeWillChange]
|
||||
public function valid()
|
||||
{
|
||||
return $this->_current !== false;
|
||||
return $this->current !== false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\Persistence\Proxy;
|
||||
|
||||
use function array_fill_keys;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function is_array;
|
||||
use function key;
|
||||
@@ -52,7 +52,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
private $existingCollections = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function prepare()
|
||||
{
|
||||
@@ -108,7 +108,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function cleanup()
|
||||
{
|
||||
@@ -139,7 +139,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
@@ -284,13 +284,17 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$class = $this->_metadataCache[$className];
|
||||
|
||||
if ($class->isIdentifierComposite) {
|
||||
$idHash = '';
|
||||
|
||||
foreach ($class->identifier as $fieldName) {
|
||||
$idHash .= ' ' . (isset($class->associationMappings[$fieldName])
|
||||
? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
|
||||
: $data[$fieldName]);
|
||||
}
|
||||
$idHash = UnitOfWork::getIdHashByIdentifier(
|
||||
array_map(
|
||||
/** @return mixed */
|
||||
static function (string $fieldName) use ($data, $class) {
|
||||
return isset($class->associationMappings[$fieldName])
|
||||
? $data[$class->associationMappings[$fieldName]['joinColumns'][0]['name']]
|
||||
: $data[$fieldName];
|
||||
},
|
||||
$class->identifier
|
||||
)
|
||||
);
|
||||
|
||||
return $this->_uow->tryGetByIdHash(ltrim($idHash), $class->rootEntityName);
|
||||
} elseif (isset($class->associationMappings[$class->identifier[0]])) {
|
||||
@@ -308,7 +312,6 @@ class ObjectHydrator extends AbstractHydrator
|
||||
* that belongs to a particular component/class. Afterwards, all these chunks
|
||||
* are processed, one after the other. For each chunk of class data only one of the
|
||||
* following code paths is executed:
|
||||
*
|
||||
* Path A: The data chunk belongs to a joined/associated object and the association
|
||||
* is collection-valued.
|
||||
* Path B: The data chunk belongs to a joined/associated object and the association
|
||||
@@ -435,7 +438,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
// PATH B: Single-valued association
|
||||
$reflFieldValue = $reflField->getValue($parentObject);
|
||||
|
||||
if (! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && ! $reflFieldValue->__isInitialized())) {
|
||||
if (! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || $this->_uow->isUninitializedObject($reflFieldValue)) {
|
||||
// we only need to take action if this value is null,
|
||||
// we refresh the entity or its an uninitialized proxy.
|
||||
if (isset($nonemptyComponents[$dqlAlias])) {
|
||||
@@ -453,9 +456,6 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($element, $parentObject);
|
||||
$this->_uow->setOriginalEntityProperty(spl_object_id($element), $inverseAssoc['fieldName'], $parentObject);
|
||||
}
|
||||
} elseif ($parentClass === $targetClass && $relation['mappedBy']) {
|
||||
// Special case: bi-directional self-referencing one-one on the same class
|
||||
$targetClass->reflFields[$relationField]->setValue($element, $parentObject);
|
||||
}
|
||||
} else {
|
||||
// For sure bidirectional, as there is no inverse side in unidirectional mappings
|
||||
|
||||
@@ -16,7 +16,7 @@ use function count;
|
||||
final class ScalarColumnHydrator extends AbstractHydrator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws MultipleSelectorsFoundException
|
||||
* @throws Exception
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Doctrine\ORM\Internal\Hydration;
|
||||
class ScalarHydrator extends AbstractHydrator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
@@ -26,7 +26,7 @@ class ScalarHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
private $class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function prepare()
|
||||
{
|
||||
@@ -44,7 +44,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function cleanup()
|
||||
{
|
||||
@@ -55,7 +55,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
@@ -71,7 +71,7 @@ class SimpleObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateRowData(array $row, array &$result)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ use function key;
|
||||
class SingleScalarHydrator extends AbstractHydrator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function hydrateAllData()
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ final class HydrationCompleteHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should me called after any hydration cycle completed.
|
||||
* This method should be called after any hydration cycle completed.
|
||||
*
|
||||
* Method fires all deferred invocations of postLoad events
|
||||
*/
|
||||
|
||||
@@ -9,7 +9,9 @@ use Doctrine\DBAL\Platforms\DB2Platform;
|
||||
use Doctrine\DBAL\Platforms\OraclePlatform;
|
||||
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
|
||||
|
||||
use function get_class;
|
||||
use function method_exists;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function strtoupper;
|
||||
|
||||
@@ -26,7 +28,7 @@ trait SQLResultCasing
|
||||
return strtolower($column);
|
||||
}
|
||||
|
||||
if (method_exists(AbstractPlatform::class, 'getSQLResultCasing')) {
|
||||
if (strpos(get_class($platform), 'Doctrine\\DBAL\\Platforms\\') !== 0 && method_exists(AbstractPlatform::class, 'getSQLResultCasing')) {
|
||||
return $platform->getSQLResultCasing($column);
|
||||
}
|
||||
|
||||
|
||||
165
lib/Doctrine/ORM/Internal/TopologicalSort.php
Normal file
165
lib/Doctrine/ORM/Internal/TopologicalSort.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal;
|
||||
|
||||
use Doctrine\ORM\Internal\TopologicalSort\CycleDetectedException;
|
||||
|
||||
use function array_keys;
|
||||
use function array_reverse;
|
||||
use function array_unshift;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
* TopologicalSort implements topological sorting, which is an ordering
|
||||
* algorithm for directed graphs (DG) using a depth-first searching (DFS)
|
||||
* to traverse the graph built in memory.
|
||||
* This algorithm has a linear running time based on nodes (V) and edges
|
||||
* between the nodes (E), resulting in a computational complexity of O(V + E).
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class TopologicalSort
|
||||
{
|
||||
private const NOT_VISITED = 1;
|
||||
private const IN_PROGRESS = 2;
|
||||
private const VISITED = 3;
|
||||
|
||||
/**
|
||||
* Array of all nodes, indexed by object ids.
|
||||
*
|
||||
* @var array<int, object>
|
||||
*/
|
||||
private $nodes = [];
|
||||
|
||||
/**
|
||||
* DFS state for the different nodes, indexed by node object id and using one of
|
||||
* this class' constants as value.
|
||||
*
|
||||
* @var array<int, self::*>
|
||||
*/
|
||||
private $states = [];
|
||||
|
||||
/**
|
||||
* Edges between the nodes. The first-level key is the object id of the outgoing
|
||||
* node; the second array maps the destination node by object id as key. The final
|
||||
* boolean value indicates whether the edge is optional or not.
|
||||
*
|
||||
* @var array<int, array<int, bool>>
|
||||
*/
|
||||
private $edges = [];
|
||||
|
||||
/**
|
||||
* Builds up the result during the DFS.
|
||||
*
|
||||
* @var list<object>
|
||||
*/
|
||||
private $sortResult = [];
|
||||
|
||||
/** @param object $node */
|
||||
public function addNode($node): void
|
||||
{
|
||||
$id = spl_object_id($node);
|
||||
$this->nodes[$id] = $node;
|
||||
$this->states[$id] = self::NOT_VISITED;
|
||||
$this->edges[$id] = [];
|
||||
}
|
||||
|
||||
/** @param object $node */
|
||||
public function hasNode($node): bool
|
||||
{
|
||||
return isset($this->nodes[spl_object_id($node)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new edge between two nodes to the graph
|
||||
*
|
||||
* @param object $from
|
||||
* @param object $to
|
||||
* @param bool $optional This indicates whether the edge may be ignored during the topological sort if it is necessary to break cycles.
|
||||
*/
|
||||
public function addEdge($from, $to, bool $optional): void
|
||||
{
|
||||
$fromId = spl_object_id($from);
|
||||
$toId = spl_object_id($to);
|
||||
|
||||
if (isset($this->edges[$fromId][$toId]) && $this->edges[$fromId][$toId] === false) {
|
||||
return; // we already know about this dependency, and it is not optional
|
||||
}
|
||||
|
||||
$this->edges[$fromId][$toId] = $optional;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a topological sort of all nodes. When we have an edge A->B between two nodes
|
||||
* A and B, then A will be listed before B in the result.
|
||||
*
|
||||
* @return list<object>
|
||||
*/
|
||||
public function sort(): array
|
||||
{
|
||||
/*
|
||||
* When possible, keep objects in the result in the same order in which they were added as nodes.
|
||||
* Since nodes are unshifted into $this->>sortResult (see the visit() method), that means we
|
||||
* need to work them in array_reverse order here.
|
||||
*/
|
||||
foreach (array_reverse(array_keys($this->nodes)) as $oid) {
|
||||
if ($this->states[$oid] === self::NOT_VISITED) {
|
||||
$this->visit($oid);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->sortResult;
|
||||
}
|
||||
|
||||
private function visit(int $oid): void
|
||||
{
|
||||
if ($this->states[$oid] === self::IN_PROGRESS) {
|
||||
// This node is already on the current DFS stack. We've found a cycle!
|
||||
throw new CycleDetectedException($this->nodes[$oid]);
|
||||
}
|
||||
|
||||
if ($this->states[$oid] === self::VISITED) {
|
||||
// We've reached a node that we've already seen, including all
|
||||
// other nodes that are reachable from here. We're done here, return.
|
||||
return;
|
||||
}
|
||||
|
||||
$this->states[$oid] = self::IN_PROGRESS;
|
||||
|
||||
// Continue the DFS downwards the edge list
|
||||
foreach ($this->edges[$oid] as $adjacentId => $optional) {
|
||||
try {
|
||||
$this->visit($adjacentId);
|
||||
} catch (CycleDetectedException $exception) {
|
||||
if ($exception->isCycleCollected()) {
|
||||
// There is a complete cycle downstream of the current node. We cannot
|
||||
// do anything about that anymore.
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
if ($optional) {
|
||||
// The current edge is part of a cycle, but it is optional and the closest
|
||||
// such edge while backtracking. Break the cycle here by skipping the edge
|
||||
// and continuing with the next one.
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have found a cycle and cannot break it at $edge. Best we can do
|
||||
// is to retreat from the current vertex, hoping that somewhere up the
|
||||
// stack this can be salvaged.
|
||||
$this->states[$oid] = self::NOT_VISITED;
|
||||
$exception->addToCycle($this->nodes[$oid]);
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
// We have traversed all edges and visited all other nodes reachable from here.
|
||||
// So we're done with this vertex as well.
|
||||
|
||||
$this->states[$oid] = self::VISITED;
|
||||
array_unshift($this->sortResult, $this->nodes[$oid]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal\TopologicalSort;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
use function array_unshift;
|
||||
|
||||
class CycleDetectedException extends RuntimeException
|
||||
{
|
||||
/** @var list<object> */
|
||||
private $cycle;
|
||||
|
||||
/** @var object */
|
||||
private $startNode;
|
||||
|
||||
/**
|
||||
* Do we have the complete cycle collected?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $cycleCollected = false;
|
||||
|
||||
/** @param object $startNode */
|
||||
public function __construct($startNode)
|
||||
{
|
||||
parent::__construct('A cycle has been detected, so a topological sort is not possible. The getCycle() method provides the list of nodes that form the cycle.');
|
||||
|
||||
$this->startNode = $startNode;
|
||||
$this->cycle = [$startNode];
|
||||
}
|
||||
|
||||
/** @return list<object> */
|
||||
public function getCycle(): array
|
||||
{
|
||||
return $this->cycle;
|
||||
}
|
||||
|
||||
/** @param object $node */
|
||||
public function addToCycle($node): void
|
||||
{
|
||||
array_unshift($this->cycle, $node);
|
||||
|
||||
if ($node === $this->startNode) {
|
||||
$this->cycleCollected = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function isCycleCollected(): bool
|
||||
{
|
||||
return $this->cycleCollected;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
use SQLResultCasing;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -24,7 +24,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getTableName(ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -32,7 +32,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -40,7 +40,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -48,7 +48,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -56,7 +56,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -64,7 +64,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -72,7 +72,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ?ClassMetadata $class = null)
|
||||
{
|
||||
|
||||
@@ -220,10 +220,11 @@ class ClassMetadataBuilder
|
||||
* @param string $type
|
||||
* @param int $length
|
||||
* @psalm-param class-string<BackedEnum>|null $enumType
|
||||
* @psalm-param array<string, mixed> $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDiscriminatorColumn($name, $type = 'string', $length = 255, ?string $columnDefinition = null, ?string $enumType = null)
|
||||
public function setDiscriminatorColumn($name, $type = 'string', $length = 255, ?string $columnDefinition = null, ?string $enumType = null, array $options = [])
|
||||
{
|
||||
$this->cm->setDiscriminatorColumn(
|
||||
[
|
||||
@@ -232,6 +233,7 @@ class ClassMetadataBuilder
|
||||
'length' => $length,
|
||||
'columnDefinition' => $columnDefinition,
|
||||
'enumType' => $enumType,
|
||||
'options' => $options,
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ final class ChainTypedFieldMapper implements TypedFieldMapper
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validateAndComplete(array $mapping, ReflectionProperty $field): array
|
||||
{
|
||||
|
||||
@@ -4,12 +4,102 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use BackedEnum;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @todo remove or rename ClassMetadataInfo to ClassMetadata
|
||||
* @template-covariant T of object
|
||||
* @template-extends ClassMetadataInfo<T>
|
||||
* @psalm-type FieldMapping = array{
|
||||
* type: string,
|
||||
* fieldName: string,
|
||||
* columnName: string,
|
||||
* length?: int,
|
||||
* id?: bool,
|
||||
* nullable?: bool,
|
||||
* notInsertable?: bool,
|
||||
* notUpdatable?: bool,
|
||||
* generated?: int,
|
||||
* enumType?: class-string<BackedEnum>,
|
||||
* columnDefinition?: string,
|
||||
* precision?: int,
|
||||
* scale?: int,
|
||||
* unique?: bool,
|
||||
* inherited?: class-string,
|
||||
* originalClass?: class-string,
|
||||
* originalField?: string,
|
||||
* quoted?: bool,
|
||||
* requireSQLConversion?: bool,
|
||||
* declared?: class-string,
|
||||
* declaredField?: string,
|
||||
* options?: array<string, mixed>,
|
||||
* version?: string,
|
||||
* default?: string|int,
|
||||
* }
|
||||
* @psalm-type JoinColumnData = array{
|
||||
* name: string,
|
||||
* referencedColumnName: string,
|
||||
* unique?: bool,
|
||||
* quoted?: bool,
|
||||
* fieldName?: string,
|
||||
* onDelete?: string,
|
||||
* columnDefinition?: string,
|
||||
* nullable?: bool,
|
||||
* }
|
||||
* @psalm-type AssociationMapping = array{
|
||||
* cache?: array,
|
||||
* cascade: array<string>,
|
||||
* declared?: class-string,
|
||||
* fetch: mixed,
|
||||
* fieldName: string,
|
||||
* id?: bool,
|
||||
* inherited?: class-string,
|
||||
* indexBy?: string,
|
||||
* inversedBy: string|null,
|
||||
* isCascadeRemove: bool,
|
||||
* isCascadePersist: bool,
|
||||
* isCascadeRefresh: bool,
|
||||
* isCascadeMerge: bool,
|
||||
* isCascadeDetach: bool,
|
||||
* isOnDeleteCascade?: bool,
|
||||
* isOwningSide: bool,
|
||||
* joinColumns?: array<JoinColumnData>,
|
||||
* joinColumnFieldNames?: array<string, string>,
|
||||
* joinTable?: array,
|
||||
* joinTableColumns?: list<mixed>,
|
||||
* mappedBy: string|null,
|
||||
* orderBy?: array,
|
||||
* originalClass?: class-string,
|
||||
* originalField?: string,
|
||||
* orphanRemoval?: bool,
|
||||
* relationToSourceKeyColumns?: array,
|
||||
* relationToTargetKeyColumns?: array,
|
||||
* sourceEntity: class-string,
|
||||
* sourceToTargetKeyColumns?: array<string, string>,
|
||||
* targetEntity: class-string,
|
||||
* targetToSourceKeyColumns?: array<string, string>,
|
||||
* type: int,
|
||||
* unique?: bool,
|
||||
* }
|
||||
* @psalm-type DiscriminatorColumnMapping = array{
|
||||
* name: string,
|
||||
* fieldName: string,
|
||||
* type: string,
|
||||
* length?: int,
|
||||
* columnDefinition?: string|null,
|
||||
* enumType?: class-string<BackedEnum>|null,
|
||||
* options?: array<string, mixed>,
|
||||
* }
|
||||
* @psalm-type EmbeddedClassMapping = array{
|
||||
* class: class-string,
|
||||
* columnPrefix: string|null,
|
||||
* declaredField: string|null,
|
||||
* originalField: string|null,
|
||||
* inherited?: class-string,
|
||||
* declared?: class-string,
|
||||
* }
|
||||
*/
|
||||
class ClassMetadata extends ClassMetadataInfo
|
||||
{
|
||||
|
||||
@@ -7,6 +7,9 @@ namespace Doctrine\ORM\Mapping;
|
||||
use Doctrine\Common\EventManager;
|
||||
use Doctrine\DBAL\Platforms;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Platforms\MySQLPlatform;
|
||||
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
||||
use Doctrine\DBAL\Platforms\SQLServerPlatform;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
|
||||
@@ -47,6 +50,9 @@ use function substr;
|
||||
* to a relational database.
|
||||
*
|
||||
* @extends AbstractClassMetadataFactory<ClassMetadata>
|
||||
* @psalm-import-type AssociationMapping from ClassMetadata
|
||||
* @psalm-import-type EmbeddedClassMapping from ClassMetadata
|
||||
* @psalm-import-type FieldMapping from ClassMetadata
|
||||
*/
|
||||
class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
{
|
||||
@@ -107,7 +113,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
if ($parent) {
|
||||
$class->setInheritanceType($parent->inheritanceType);
|
||||
$class->setDiscriminatorColumn($parent->discriminatorColumn);
|
||||
$class->setIdGeneratorType($parent->generatorType);
|
||||
$this->inheritIdGeneratorMapping($class, $parent);
|
||||
$this->addInheritedFields($class, $parent);
|
||||
$this->addInheritedRelations($class, $parent);
|
||||
$this->addInheritedEmbeddedClasses($class, $parent);
|
||||
@@ -135,25 +141,27 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
throw MappingException::reflectionFailure($class->getName(), $e);
|
||||
}
|
||||
|
||||
// If this class has a parent the id generator strategy is inherited.
|
||||
// However this is only true if the hierarchy of parents contains the root entity,
|
||||
// if it consists of mapped superclasses these don't necessarily include the id field.
|
||||
if ($parent && $rootEntityFound) {
|
||||
$this->inheritIdGeneratorMapping($class, $parent);
|
||||
} else {
|
||||
// Complete id generator mapping when the generator was declared/added in this class
|
||||
if ($class->identifier && (! $parent || ! $parent->identifier)) {
|
||||
$this->completeIdGeneratorMapping($class);
|
||||
}
|
||||
|
||||
if (! $class->isMappedSuperclass) {
|
||||
if ($rootEntityFound && $class->isInheritanceTypeNone()) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10431',
|
||||
"Entity class '%s' is a subclass of the root entity class '%s', but no inheritance mapping type was declared. This is a misconfiguration and will be an error in Doctrine ORM 3.0.",
|
||||
$class->name,
|
||||
end($nonSuperclassParents)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($class->embeddedClasses as $property => $embeddableClass) {
|
||||
if (isset($embeddableClass['inherited'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! (isset($embeddableClass['class']) && $embeddableClass['class'])) {
|
||||
throw MappingException::missingEmbeddedClass($property);
|
||||
}
|
||||
|
||||
if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) {
|
||||
throw MappingException::infiniteEmbeddableNesting($class->name, $property);
|
||||
}
|
||||
@@ -411,20 +419,30 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
return strtolower(end($parts));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the `inherited` and `declared` values into mapping information for fields, associations
|
||||
* and embedded classes.
|
||||
*
|
||||
* @param AssociationMapping|EmbeddedClassMapping|FieldMapping $mapping
|
||||
*/
|
||||
private function addMappingInheritanceInformation(array &$mapping, ClassMetadata $parentClass): void
|
||||
{
|
||||
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$mapping['inherited'] = $parentClass->name;
|
||||
}
|
||||
|
||||
if (! isset($mapping['declared'])) {
|
||||
$mapping['declared'] = $parentClass->name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds inherited fields to the subclass mapping.
|
||||
*/
|
||||
private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass): void
|
||||
{
|
||||
foreach ($parentClass->fieldMappings as $mapping) {
|
||||
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$mapping['inherited'] = $parentClass->name;
|
||||
}
|
||||
|
||||
if (! isset($mapping['declared'])) {
|
||||
$mapping['declared'] = $parentClass->name;
|
||||
}
|
||||
|
||||
$this->addMappingInheritanceInformation($mapping, $parentClass);
|
||||
$subClass->addInheritedFieldMapping($mapping);
|
||||
}
|
||||
|
||||
@@ -441,14 +459,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass): void
|
||||
{
|
||||
foreach ($parentClass->associationMappings as $field => $mapping) {
|
||||
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$mapping['inherited'] = $parentClass->name;
|
||||
}
|
||||
|
||||
if (! isset($mapping['declared'])) {
|
||||
$mapping['declared'] = $parentClass->name;
|
||||
}
|
||||
|
||||
$this->addMappingInheritanceInformation($mapping, $parentClass);
|
||||
// When the class inheriting the relation ($subClass) is the first entity class since the
|
||||
// relation has been defined in a mapped superclass (or in a chain
|
||||
// of mapped superclasses) above, then declare this current entity class as the source of
|
||||
@@ -456,10 +467,6 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
// According to the definitions given in https://github.com/doctrine/orm/pull/10396/,
|
||||
// this is the case <=> ! isset($mapping['inherited']).
|
||||
if (! isset($mapping['inherited'])) {
|
||||
if ($mapping['type'] & ClassMetadata::TO_MANY && ! $mapping['isOwningSide']) {
|
||||
throw MappingException::illegalToManyAssociationOnMappedSuperclass($parentClass->name, $field);
|
||||
}
|
||||
|
||||
$mapping['sourceEntity'] = $subClass->name;
|
||||
}
|
||||
|
||||
@@ -470,14 +477,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
private function addInheritedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass): void
|
||||
{
|
||||
foreach ($parentClass->embeddedClasses as $field => $embeddedClass) {
|
||||
if (! isset($embeddedClass['inherited']) && ! $parentClass->isMappedSuperclass) {
|
||||
$embeddedClass['inherited'] = $parentClass->name;
|
||||
}
|
||||
|
||||
if (! isset($embeddedClass['declared'])) {
|
||||
$embeddedClass['declared'] = $parentClass->name;
|
||||
}
|
||||
|
||||
$this->addMappingInheritanceInformation($embeddedClass, $parentClass);
|
||||
$subClass->embeddedClasses[$field] = $embeddedClass;
|
||||
}
|
||||
}
|
||||
@@ -620,9 +620,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
case ClassMetadata::GENERATOR_TYPE_IDENTITY:
|
||||
$sequenceName = null;
|
||||
$fieldName = $class->identifier ? $class->getSingleIdentifierFieldName() : null;
|
||||
$platform = $this->getTargetPlatform();
|
||||
|
||||
// Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
|
||||
if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) {
|
||||
/** @psalm-suppress UndefinedClass, InvalidClass */
|
||||
if (! $platform instanceof MySQLPlatform && ! $platform instanceof SqlitePlatform && ! $platform instanceof SQLServerPlatform && $platform->usesSequenceEmulatedIdentityColumns()) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/8850',
|
||||
|
||||
@@ -68,83 +68,11 @@ use const PHP_VERSION_ID;
|
||||
*
|
||||
* @template-covariant T of object
|
||||
* @template-implements ClassMetadata<T>
|
||||
* @psalm-type FieldMapping = array{
|
||||
* type: string,
|
||||
* fieldName: string,
|
||||
* columnName: string,
|
||||
* length?: int,
|
||||
* id?: bool,
|
||||
* nullable?: bool,
|
||||
* notInsertable?: bool,
|
||||
* notUpdatable?: bool,
|
||||
* generated?: int,
|
||||
* enumType?: class-string<BackedEnum>,
|
||||
* columnDefinition?: string,
|
||||
* precision?: int,
|
||||
* scale?: int,
|
||||
* unique?: bool,
|
||||
* inherited?: class-string,
|
||||
* originalClass?: class-string,
|
||||
* originalField?: string,
|
||||
* quoted?: bool,
|
||||
* requireSQLConversion?: bool,
|
||||
* declared?: class-string,
|
||||
* declaredField?: string,
|
||||
* options?: array<string, mixed>
|
||||
* }
|
||||
* @psalm-type JoinColumnData = array{
|
||||
* name: string,
|
||||
* referencedColumnName: string,
|
||||
* unique?: bool,
|
||||
* quoted?: bool,
|
||||
* fieldName?: string,
|
||||
* onDelete?: string,
|
||||
* columnDefinition?: string,
|
||||
* nullable?: bool,
|
||||
* }
|
||||
* @psalm-type AssociationMapping = array{
|
||||
* cache?: array,
|
||||
* cascade: array<string>,
|
||||
* declared?: class-string,
|
||||
* fetch: mixed,
|
||||
* fieldName: string,
|
||||
* id?: bool,
|
||||
* inherited?: class-string,
|
||||
* indexBy?: string,
|
||||
* inversedBy: string|null,
|
||||
* isCascadeRemove: bool,
|
||||
* isCascadePersist: bool,
|
||||
* isCascadeRefresh: bool,
|
||||
* isCascadeMerge: bool,
|
||||
* isCascadeDetach: bool,
|
||||
* isOnDeleteCascade?: bool,
|
||||
* isOwningSide: bool,
|
||||
* joinColumns?: array<JoinColumnData>,
|
||||
* joinColumnFieldNames?: array<string, string>,
|
||||
* joinTable?: array,
|
||||
* joinTableColumns?: list<mixed>,
|
||||
* mappedBy: string|null,
|
||||
* orderBy?: array,
|
||||
* originalClass?: class-string,
|
||||
* originalField?: string,
|
||||
* orphanRemoval?: bool,
|
||||
* relationToSourceKeyColumns?: array,
|
||||
* relationToTargetKeyColumns?: array,
|
||||
* sourceEntity: class-string,
|
||||
* sourceToTargetKeyColumns?: array<string, string>,
|
||||
* targetEntity: class-string,
|
||||
* targetToSourceKeyColumns?: array<string, string>,
|
||||
* type: int,
|
||||
* unique?: bool,
|
||||
* }
|
||||
* @psalm-type DiscriminatorColumnMapping = array{
|
||||
* name: string,
|
||||
* fieldName: string,
|
||||
* type: string,
|
||||
* length?: int,
|
||||
* columnDefinition?: string|null,
|
||||
* enumType?: class-string<BackedEnum>|null,
|
||||
* }
|
||||
* @psalm-import-type AssociationMapping from \Doctrine\ORM\Mapping\ClassMetadata
|
||||
* @psalm-import-type FieldMapping from \Doctrine\ORM\Mapping\ClassMetadata
|
||||
* @psalm-import-type EmbeddedClassMapping from \Doctrine\ORM\Mapping\ClassMetadata
|
||||
* @psalm-import-type JoinColumnData from \Doctrine\ORM\Mapping\ClassMetadata
|
||||
* @psalm-import-type DiscriminatorColumnMapping from \Doctrine\ORM\Mapping\ClassMetadata
|
||||
*/
|
||||
class ClassMetadataInfo implements ClassMetadata
|
||||
{
|
||||
@@ -170,6 +98,8 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* TABLE_PER_CLASS means the class will be persisted according to the rules
|
||||
* of <tt>Concrete Table Inheritance</tt>.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public const INHERITANCE_TYPE_TABLE_PER_CLASS = 4;
|
||||
|
||||
@@ -390,7 +320,8 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
public $isEmbeddedClass = false;
|
||||
|
||||
/**
|
||||
* READ-ONLY: The names of the parent classes (ancestors).
|
||||
* READ-ONLY: The names of the parent <em>entity</em> classes (ancestors), starting with the
|
||||
* nearest one and ending with the root entity class.
|
||||
*
|
||||
* @psalm-var list<class-string>
|
||||
*/
|
||||
@@ -442,7 +373,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* declared in another parent <em>entity or mapped superclass</em>. The value is the FQCN
|
||||
* of the topmost non-transient class that contains mapping information for this field.
|
||||
*
|
||||
* @psalm-var array<string, mixed[]>
|
||||
* @psalm-var array<string, EmbeddedClassMapping>
|
||||
*/
|
||||
public $embeddedClasses = [];
|
||||
|
||||
@@ -1166,6 +1097,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
foreach ($this->embeddedClasses as $property => $embeddedClass) {
|
||||
if (isset($embeddedClass['declaredField'])) {
|
||||
assert($embeddedClass['originalField'] !== null);
|
||||
$childProperty = $this->getAccessibleProperty(
|
||||
$reflService,
|
||||
$this->embeddedClasses[$embeddedClass['declaredField']]['class'],
|
||||
@@ -1244,7 +1176,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
$this->namespace = $reflService->getClassNamespace($this->name);
|
||||
|
||||
if ($this->reflClass) {
|
||||
$this->name = $this->rootEntityName = $this->reflClass->getName();
|
||||
$this->name = $this->rootEntityName = $this->reflClass->name;
|
||||
}
|
||||
|
||||
$this->table['name'] = $this->namingStrategy->classToTableName($this->name);
|
||||
@@ -1651,9 +1583,9 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* Validates & completes the given field mapping based on typed property.
|
||||
*
|
||||
* @param array{fieldName: string, type?: mixed} $mapping The field mapping to validate & complete.
|
||||
* @param array{fieldName: string, type?: string} $mapping The field mapping to validate & complete.
|
||||
*
|
||||
* @return array{fieldName: string, enumType?: string, type?: mixed} The updated mapping.
|
||||
* @return array{fieldName: string, enumType?: class-string<BackedEnum>, type?: string} The updated mapping.
|
||||
*/
|
||||
private function validateAndCompleteTypedFieldMapping(array $mapping): array
|
||||
{
|
||||
@@ -1697,7 +1629,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* enumType?: class-string,
|
||||
* } $mapping The field mapping to validate & complete.
|
||||
*
|
||||
* @return mixed[] The updated mapping.
|
||||
* @return FieldMapping The updated mapping.
|
||||
*
|
||||
* @throws MappingException
|
||||
*/
|
||||
@@ -1923,30 +1855,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* @psalm-param array<string, mixed> $mapping The mapping to validate & complete.
|
||||
*
|
||||
* @return mixed[] The validated & completed mapping.
|
||||
* @psalm-return array{
|
||||
* mappedBy: mixed|null,
|
||||
* inversedBy: mixed|null,
|
||||
* isOwningSide: bool,
|
||||
* sourceEntity: class-string,
|
||||
* targetEntity: string,
|
||||
* fieldName: mixed,
|
||||
* fetch: mixed,
|
||||
* cascade: array<string>,
|
||||
* isCascadeRemove: bool,
|
||||
* isCascadePersist: bool,
|
||||
* isCascadeRefresh: bool,
|
||||
* isCascadeMerge: bool,
|
||||
* isCascadeDetach: bool,
|
||||
* type: int,
|
||||
* originalField: string,
|
||||
* originalClass: class-string,
|
||||
* joinColumns?: array{0: array{name: string, referencedColumnName: string}}|mixed,
|
||||
* id?: mixed,
|
||||
* sourceToTargetKeyColumns?: array<string, string>,
|
||||
* joinColumnFieldNames?: array<string, string>,
|
||||
* targetToSourceKeyColumns?: array<string, string>,
|
||||
* orphanRemoval: bool
|
||||
* }
|
||||
* @psalm-return AssociationMapping
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @throws MappingException
|
||||
@@ -1955,6 +1864,14 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
{
|
||||
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
|
||||
|
||||
if (isset($mapping['joinColumns']) && $mapping['joinColumns'] && ! $mapping['isOwningSide']) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10654',
|
||||
'JoinColumn configuration is not allowed on the inverse side of one-to-one associations, and will throw a MappingException in Doctrine ORM 3.0'
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
|
||||
$mapping['isOwningSide'] = true;
|
||||
}
|
||||
@@ -2036,22 +1953,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* @psalm-param array<string, mixed> $mapping The mapping to validate and complete.
|
||||
*
|
||||
* @return mixed[] The validated and completed mapping.
|
||||
* @psalm-return array{
|
||||
* mappedBy: mixed,
|
||||
* inversedBy: mixed,
|
||||
* isOwningSide: bool,
|
||||
* sourceEntity: string,
|
||||
* targetEntity: string,
|
||||
* fieldName: mixed,
|
||||
* fetch: int|mixed,
|
||||
* cascade: array<array-key,string>,
|
||||
* isCascadeRemove: bool,
|
||||
* isCascadePersist: bool,
|
||||
* isCascadeRefresh: bool,
|
||||
* isCascadeMerge: bool,
|
||||
* isCascadeDetach: bool,
|
||||
* orphanRemoval: bool
|
||||
* }
|
||||
* @psalm-return AssociationMapping
|
||||
*
|
||||
* @throws MappingException
|
||||
* @throws InvalidArgumentException
|
||||
@@ -2079,30 +1981,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* @psalm-param array<string, mixed> $mapping The mapping to validate & complete.
|
||||
*
|
||||
* @return mixed[] The validated & completed mapping.
|
||||
* @psalm-return array{
|
||||
* mappedBy: mixed,
|
||||
* inversedBy: mixed,
|
||||
* isOwningSide: bool,
|
||||
* sourceEntity: class-string,
|
||||
* targetEntity: string,
|
||||
* fieldName: mixed,
|
||||
* fetch: mixed,
|
||||
* cascade: array<string>,
|
||||
* isCascadeRemove: bool,
|
||||
* isCascadePersist: bool,
|
||||
* isCascadeRefresh: bool,
|
||||
* isCascadeMerge: bool,
|
||||
* isCascadeDetach: bool,
|
||||
* type: int,
|
||||
* originalField: string,
|
||||
* originalClass: class-string,
|
||||
* joinTable?: array{inverseJoinColumns: mixed}|mixed,
|
||||
* joinTableColumns?: list<mixed>,
|
||||
* isOnDeleteCascade?: true,
|
||||
* relationToSourceKeyColumns?: array,
|
||||
* relationToTargetKeyColumns?: array,
|
||||
* orphanRemoval: bool
|
||||
* }
|
||||
* @psalm-return AssociationMapping
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
@@ -2375,11 +2254,19 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* Checks whether the mapped class uses the TABLE_PER_CLASS inheritance mapping strategy.
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @return bool TRUE if the class participates in a TABLE_PER_CLASS inheritance mapping,
|
||||
* FALSE otherwise.
|
||||
*/
|
||||
public function isInheritanceTypeTablePerClass()
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10414/',
|
||||
'Concrete table inheritance has never been implemented, and its stubs will be removed in Doctrine ORM 3.0 with no replacement'
|
||||
);
|
||||
|
||||
return $this->inheritanceType === self::INHERITANCE_TYPE_TABLE_PER_CLASS;
|
||||
}
|
||||
|
||||
@@ -2531,7 +2418,8 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent class names.
|
||||
* Sets the parent class names. Only <em>entity</em> classes may be given.
|
||||
*
|
||||
* Assumes that the class names in the passed array are in the order:
|
||||
* directParent -> directParentParent -> directParentParentParent ... -> root.
|
||||
*
|
||||
@@ -2585,12 +2473,16 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
$mapping = $this->associationMappings[$fieldName];
|
||||
|
||||
//if (isset($mapping['inherited']) && (count($overrideMapping) !== 1 || ! isset($overrideMapping['fetch']))) {
|
||||
// TODO: Deprecate overriding the fetch mode via association override for 3.0,
|
||||
// users should do this with a listener and a custom attribute/annotation
|
||||
// TODO: Enable this exception in 2.8
|
||||
//throw MappingException::illegalOverrideOfInheritedProperty($this->name, $fieldName);
|
||||
//}
|
||||
if (isset($mapping['inherited'])) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10470',
|
||||
'Overrides are only allowed for fields or associations declared in mapped superclasses or traits. This is not the case for %s::%s, which was inherited from %s. This is a misconfiguration and will be an error in Doctrine ORM 3.0.',
|
||||
$this->name,
|
||||
$fieldName,
|
||||
$mapping['inherited']
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($overrideMapping['joinColumns'])) {
|
||||
$mapping['joinColumns'] = $overrideMapping['joinColumns'];
|
||||
@@ -2650,10 +2542,17 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
$mapping = $this->fieldMappings[$fieldName];
|
||||
|
||||
//if (isset($mapping['inherited'])) {
|
||||
// TODO: Enable this exception in 2.8
|
||||
if (isset($mapping['inherited'])) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10470',
|
||||
'Overrides are only allowed for fields or associations declared in mapped superclasses or traits. This is not the case for %s::%s, which was inherited from %s. This is a misconfiguration and will be an error in Doctrine ORM 3.0.',
|
||||
$this->name,
|
||||
$fieldName,
|
||||
$mapping['inherited']
|
||||
);
|
||||
//throw MappingException::illegalOverrideOfInheritedProperty($this->name, $fieldName);
|
||||
//}
|
||||
}
|
||||
|
||||
if (isset($mapping['id'])) {
|
||||
$overrideMapping['id'] = $mapping['id'];
|
||||
@@ -2796,6 +2695,14 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
private function isInheritanceType(int $type): bool
|
||||
{
|
||||
if ($type === self::INHERITANCE_TYPE_TABLE_PER_CLASS) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10414/',
|
||||
'Concrete table inheritance has never been implemented, and its stubs will be removed in Doctrine ORM 3.0 with no replacement'
|
||||
);
|
||||
}
|
||||
|
||||
return $type === self::INHERITANCE_TYPE_NONE ||
|
||||
$type === self::INHERITANCE_TYPE_SINGLE_TABLE ||
|
||||
$type === self::INHERITANCE_TYPE_JOINED ||
|
||||
@@ -2848,7 +2755,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* Adds a field mapping without completing/validating it.
|
||||
* This is mainly used to add inherited field mappings to derived classes.
|
||||
*
|
||||
* @psalm-param array<string, mixed> $fieldMapping
|
||||
* @psalm-param FieldMapping $fieldMapping
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -2857,6 +2764,10 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
$this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
|
||||
$this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
|
||||
$this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
|
||||
|
||||
if (isset($fieldMapping['generated'])) {
|
||||
$this->requiresFetchAfterChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3084,7 +2995,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* Stores the association mapping.
|
||||
*
|
||||
* @psalm-param array<string, mixed> $assocMapping
|
||||
* @psalm-param AssociationMapping $assocMapping
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -3236,7 +3147,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* @see getDiscriminatorColumn()
|
||||
*
|
||||
* @param mixed[]|null $columnDef
|
||||
* @psalm-param array{name: string|null, fieldName?: string, type?: string, length?: int, columnDefinition?: string|null, enumType?: class-string<BackedEnum>|null}|null $columnDef
|
||||
* @psalm-param array{name: string|null, fieldName?: string, type?: string, length?: int, columnDefinition?: string|null, enumType?: class-string<BackedEnum>|null, options?: array<string, mixed>}|null $columnDef
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -3841,8 +3752,16 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
if (! (isset($mapping['class']) && $mapping['class'])) {
|
||||
throw MappingException::missingEmbeddedClass($mapping['fieldName']);
|
||||
}
|
||||
|
||||
$fqcn = $this->fullyQualifiedClassName($mapping['class']);
|
||||
|
||||
assert($fqcn !== null);
|
||||
|
||||
$this->embeddedClasses[$mapping['fieldName']] = [
|
||||
'class' => $this->fullyQualifiedClassName($mapping['class']),
|
||||
'class' => $fqcn,
|
||||
'columnPrefix' => $mapping['columnPrefix'] ?? null,
|
||||
'declaredField' => $mapping['declaredField'] ?? null,
|
||||
'originalField' => $mapping['originalField'] ?? null,
|
||||
@@ -3934,7 +3853,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
return $sequencePrefix;
|
||||
}
|
||||
|
||||
/** @psalm-param array<string, mixed> $mapping */
|
||||
/** @psalm-param AssociationMapping $mapping */
|
||||
private function assertMappingOrderBy(array $mapping): void
|
||||
{
|
||||
if (isset($mapping['orderBy']) && ! is_array($mapping['orderBy'])) {
|
||||
@@ -3947,7 +3866,14 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
{
|
||||
$reflectionProperty = $reflService->getAccessibleProperty($class, $field);
|
||||
if ($reflectionProperty !== null && PHP_VERSION_ID >= 80100 && $reflectionProperty->isReadOnly()) {
|
||||
$reflectionProperty = new ReflectionReadonlyProperty($reflectionProperty);
|
||||
$declaringClass = $reflectionProperty->class;
|
||||
if ($declaringClass !== $class) {
|
||||
$reflectionProperty = $reflService->getAccessibleProperty($declaringClass, $field);
|
||||
}
|
||||
|
||||
if ($reflectionProperty !== null) {
|
||||
$reflectionProperty = new ReflectionReadonlyProperty($reflectionProperty);
|
||||
}
|
||||
}
|
||||
|
||||
return $reflectionProperty;
|
||||
|
||||
@@ -21,7 +21,7 @@ class DefaultEntityListenerResolver implements EntityListenerResolver
|
||||
private $instances = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function clear($className = null)
|
||||
{
|
||||
@@ -38,7 +38,7 @@ class DefaultEntityListenerResolver implements EntityListenerResolver
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function register($object)
|
||||
{
|
||||
@@ -50,7 +50,7 @@ class DefaultEntityListenerResolver implements EntityListenerResolver
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function resolve($className)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ use function substr;
|
||||
class DefaultNamingStrategy implements NamingStrategy
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function classToTableName($className)
|
||||
{
|
||||
@@ -29,7 +29,7 @@ class DefaultNamingStrategy implements NamingStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function propertyToColumnName($propertyName, $className = null)
|
||||
{
|
||||
@@ -37,7 +37,7 @@ class DefaultNamingStrategy implements NamingStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function embeddedFieldToColumnName($propertyName, $embeddedColumnName, $className = null, $embeddedClassName = null)
|
||||
{
|
||||
@@ -45,7 +45,7 @@ class DefaultNamingStrategy implements NamingStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function referenceColumnName()
|
||||
{
|
||||
@@ -53,7 +53,7 @@ class DefaultNamingStrategy implements NamingStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param string $propertyName
|
||||
* @param class-string $className
|
||||
@@ -64,7 +64,7 @@ class DefaultNamingStrategy implements NamingStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function joinTableName($sourceEntity, $targetEntity, $propertyName = null)
|
||||
{
|
||||
@@ -73,7 +73,7 @@ class DefaultNamingStrategy implements NamingStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function joinKeyColumnName($entityName, $referencedColumnName = null)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
use SQLResultCasing;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -31,7 +31,7 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @todo Table names should be computed in DBAL depending on the platform
|
||||
*/
|
||||
@@ -53,7 +53,7 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -63,7 +63,7 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -73,7 +73,7 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -83,7 +83,7 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -104,7 +104,7 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform)
|
||||
{
|
||||
@@ -135,7 +135,7 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ?ClassMetadata $class = null)
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ final class DefaultTypedFieldMapper implements TypedFieldMapper
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function validateAndComplete(array $mapping, ReflectionProperty $field): array
|
||||
{
|
||||
|
||||
@@ -45,18 +45,29 @@ final class DiscriminatorColumn implements MappingAttribute
|
||||
*/
|
||||
public $enumType = null;
|
||||
|
||||
/** @param class-string<\BackedEnum>|null $enumType */
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
* @readonly
|
||||
*/
|
||||
public $options = [];
|
||||
|
||||
/**
|
||||
* @param class-string<\BackedEnum>|null $enumType
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
?string $type = null,
|
||||
?int $length = null,
|
||||
?string $columnDefinition = null,
|
||||
?string $enumType = null
|
||||
?string $enumType = null,
|
||||
array $options = []
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->type = $type;
|
||||
$this->length = $length;
|
||||
$this->columnDefinition = $columnDefinition;
|
||||
$this->enumType = $enumType;
|
||||
$this->options = $options;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ use function is_numeric;
|
||||
class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
{
|
||||
use ColocatedMappingDriver;
|
||||
use ReflectionBasedDriver;
|
||||
|
||||
/**
|
||||
* The annotation reader.
|
||||
@@ -60,7 +61,7 @@ class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
* @param Reader $reader The AnnotationReader to use
|
||||
* @param string|string[]|null $paths One or multiple paths where mapping classes can be found.
|
||||
*/
|
||||
public function __construct($reader, $paths = null)
|
||||
public function __construct($reader, $paths = null, bool $reportFieldsWhereDeclared = false)
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -70,6 +71,17 @@ class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
$this->reader = $reader;
|
||||
|
||||
$this->addPaths((array) $paths);
|
||||
|
||||
if (! $reportFieldsWhereDeclared) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10455',
|
||||
'In ORM 3.0, the AttributeDriver will report fields for the classes where they are declared. This may uncover invalid mapping configurations. To opt into the new mode also with the AnnotationDriver today, set the "reportFieldsWhereDeclared" constructor parameter to true.',
|
||||
self::class
|
||||
);
|
||||
}
|
||||
|
||||
$this->reportFieldsWhereDeclared = $reportFieldsWhereDeclared;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -313,15 +325,19 @@ class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
$discrColumnAnnot = $classAnnotations[Mapping\DiscriminatorColumn::class];
|
||||
assert($discrColumnAnnot instanceof Mapping\DiscriminatorColumn);
|
||||
|
||||
$metadata->setDiscriminatorColumn(
|
||||
[
|
||||
'name' => $discrColumnAnnot->name,
|
||||
'type' => $discrColumnAnnot->type ?: 'string',
|
||||
'length' => $discrColumnAnnot->length ?? 255,
|
||||
'columnDefinition' => $discrColumnAnnot->columnDefinition,
|
||||
'enumType' => $discrColumnAnnot->enumType,
|
||||
]
|
||||
);
|
||||
$columnDef = [
|
||||
'name' => $discrColumnAnnot->name,
|
||||
'type' => $discrColumnAnnot->type ?: 'string',
|
||||
'length' => $discrColumnAnnot->length ?? 255,
|
||||
'columnDefinition' => $discrColumnAnnot->columnDefinition,
|
||||
'enumType' => $discrColumnAnnot->enumType,
|
||||
];
|
||||
|
||||
if ($discrColumnAnnot->options) {
|
||||
$columnDef['options'] = $discrColumnAnnot->options;
|
||||
}
|
||||
|
||||
$metadata->setDiscriminatorColumn($columnDef);
|
||||
} else {
|
||||
$metadata->setDiscriminatorColumn(['name' => 'dtype', 'type' => 'string', 'length' => 255]);
|
||||
}
|
||||
@@ -344,20 +360,12 @@ class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
|
||||
// Evaluate annotations on properties/fields
|
||||
foreach ($class->getProperties() as $property) {
|
||||
if (
|
||||
$metadata->isMappedSuperclass && ! $property->isPrivate()
|
||||
||
|
||||
$metadata->isInheritedField($property->name)
|
||||
||
|
||||
$metadata->isInheritedAssociation($property->name)
|
||||
||
|
||||
$metadata->isInheritedEmbeddedClass($property->name)
|
||||
) {
|
||||
if ($this->isRepeatedPropertyDeclaration($property, $metadata)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$mapping = [];
|
||||
$mapping['fieldName'] = $property->getName();
|
||||
$mapping['fieldName'] = $property->name;
|
||||
|
||||
// Evaluate @Cache annotation
|
||||
$cacheAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Cache::class);
|
||||
@@ -390,7 +398,7 @@ class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
// @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
|
||||
$columnAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Column::class);
|
||||
if ($columnAnnot) {
|
||||
$mapping = $this->columnToArray($property->getName(), $columnAnnot);
|
||||
$mapping = $this->columnToArray($property->name, $columnAnnot);
|
||||
|
||||
$idAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Id::class);
|
||||
if ($idAnnot) {
|
||||
|
||||
@@ -23,13 +23,13 @@ use function class_exists;
|
||||
use function constant;
|
||||
use function defined;
|
||||
use function get_class;
|
||||
use function sprintf;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
{
|
||||
use ColocatedMappingDriver;
|
||||
use ReflectionBasedDriver;
|
||||
|
||||
private const ENTITY_ATTRIBUTE_CLASSES = [
|
||||
Mapping\Entity::class => 1,
|
||||
@@ -53,13 +53,13 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
protected $reader;
|
||||
|
||||
/** @param array<string> $paths */
|
||||
public function __construct(array $paths)
|
||||
public function __construct(array $paths, bool $reportFieldsWhereDeclared = false)
|
||||
{
|
||||
if (PHP_VERSION_ID < 80000) {
|
||||
throw new LogicException(sprintf(
|
||||
throw new LogicException(
|
||||
'The attribute metadata driver cannot be enabled on PHP 7. Please upgrade to PHP 8 or choose a different'
|
||||
. ' metadata driver.'
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
$this->reader = new AttributeReader();
|
||||
@@ -73,6 +73,17 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
self::class
|
||||
);
|
||||
}
|
||||
|
||||
if (! $reportFieldsWhereDeclared) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/10455',
|
||||
'In ORM 3.0, the AttributeDriver will report fields for the classes where they are declared. This may uncover invalid mapping configurations. To opt into the new mode today, set the "reportFieldsWhereDeclared" constructor parameter to true.',
|
||||
self::class
|
||||
);
|
||||
}
|
||||
|
||||
$this->reportFieldsWhereDeclared = $reportFieldsWhereDeclared;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,15 +276,19 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
if (isset($classAttributes[Mapping\DiscriminatorColumn::class])) {
|
||||
$discrColumnAttribute = $classAttributes[Mapping\DiscriminatorColumn::class];
|
||||
|
||||
$metadata->setDiscriminatorColumn(
|
||||
[
|
||||
'name' => isset($discrColumnAttribute->name) ? (string) $discrColumnAttribute->name : null,
|
||||
'type' => isset($discrColumnAttribute->type) ? (string) $discrColumnAttribute->type : 'string',
|
||||
'length' => isset($discrColumnAttribute->length) ? (int) $discrColumnAttribute->length : 255,
|
||||
'columnDefinition' => isset($discrColumnAttribute->columnDefinition) ? (string) $discrColumnAttribute->columnDefinition : null,
|
||||
'enumType' => isset($discrColumnAttribute->enumType) ? (string) $discrColumnAttribute->enumType : null,
|
||||
]
|
||||
);
|
||||
$columnDef = [
|
||||
'name' => isset($discrColumnAttribute->name) ? (string) $discrColumnAttribute->name : null,
|
||||
'type' => isset($discrColumnAttribute->type) ? (string) $discrColumnAttribute->type : 'string',
|
||||
'length' => isset($discrColumnAttribute->length) ? (int) $discrColumnAttribute->length : 255,
|
||||
'columnDefinition' => isset($discrColumnAttribute->columnDefinition) ? (string) $discrColumnAttribute->columnDefinition : null,
|
||||
'enumType' => isset($discrColumnAttribute->enumType) ? (string) $discrColumnAttribute->enumType : null,
|
||||
];
|
||||
|
||||
if ($discrColumnAttribute->options) {
|
||||
$columnDef['options'] = (array) $discrColumnAttribute->options;
|
||||
}
|
||||
|
||||
$metadata->setDiscriminatorColumn($columnDef);
|
||||
} else {
|
||||
$metadata->setDiscriminatorColumn(['name' => 'dtype', 'type' => 'string', 'length' => 255]);
|
||||
}
|
||||
@@ -294,20 +309,13 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
|
||||
foreach ($reflectionClass->getProperties() as $property) {
|
||||
assert($property instanceof ReflectionProperty);
|
||||
if (
|
||||
$metadata->isMappedSuperclass && ! $property->isPrivate()
|
||||
||
|
||||
$metadata->isInheritedField($property->name)
|
||||
||
|
||||
$metadata->isInheritedAssociation($property->name)
|
||||
||
|
||||
$metadata->isInheritedEmbeddedClass($property->name)
|
||||
) {
|
||||
|
||||
if ($this->isRepeatedPropertyDeclaration($property, $metadata)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$mapping = [];
|
||||
$mapping['fieldName'] = $property->getName();
|
||||
$mapping['fieldName'] = $property->name;
|
||||
|
||||
// Evaluate #[Cache] attribute
|
||||
$cacheAttribute = $this->reader->getPropertyAttribute($property, Mapping\Cache::class);
|
||||
@@ -342,7 +350,7 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
$embeddedAttribute = $this->reader->getPropertyAttribute($property, Mapping\Embedded::class);
|
||||
|
||||
if ($columnAttribute !== null) {
|
||||
$mapping = $this->columnToArray($property->getName(), $columnAttribute);
|
||||
$mapping = $this->columnToArray($property->name, $columnAttribute);
|
||||
|
||||
if ($this->reader->getPropertyAttribute($property, Mapping\Id::class)) {
|
||||
$mapping['id'] = true;
|
||||
@@ -433,6 +441,14 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
if ($joinTableAttribute->options) {
|
||||
$joinTable['options'] = $joinTableAttribute->options;
|
||||
}
|
||||
|
||||
foreach ($joinTableAttribute->joinColumns as $joinColumn) {
|
||||
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
|
||||
}
|
||||
|
||||
foreach ($joinTableAttribute->inverseJoinColumns as $joinColumn) {
|
||||
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->reader->getPropertyAttributeCollection($property, Mapping\JoinColumn::class) as $joinColumn) {
|
||||
|
||||
@@ -61,7 +61,7 @@ class DatabaseDriver implements MappingDriver
|
||||
private const JSON_ARRAY = 'json_array';
|
||||
|
||||
/** @var AbstractSchemaManager */
|
||||
private $_sm;
|
||||
private $sm;
|
||||
|
||||
/** @var array<string,Table>|null */
|
||||
private $tables = null;
|
||||
@@ -90,7 +90,7 @@ class DatabaseDriver implements MappingDriver
|
||||
|
||||
public function __construct(AbstractSchemaManager $schemaManager)
|
||||
{
|
||||
$this->_sm = $schemaManager;
|
||||
$this->sm = $schemaManager;
|
||||
$this->inflector = InflectorFactory::create()->build();
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ class DatabaseDriver implements MappingDriver
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/249',
|
||||
'Passing an instance of %s to %s is deprecated, please pass a ClassMetadata instance instead.',
|
||||
'Passing an instance of %s to %s is deprecated, please pass a %s instance instead.',
|
||||
get_class($metadata),
|
||||
__METHOD__,
|
||||
ClassMetadata::class
|
||||
@@ -294,7 +294,7 @@ class DatabaseDriver implements MappingDriver
|
||||
|
||||
$this->tables = $this->manyToManyTables = $this->classToTableNames = [];
|
||||
|
||||
foreach ($this->_sm->listTables() as $table) {
|
||||
foreach ($this->sm->listTables() as $table) {
|
||||
$tableName = $table->getName();
|
||||
$foreignKeys = $table->getForeignKeys();
|
||||
|
||||
|
||||
54
lib/Doctrine/ORM/Mapping/Driver/ReflectionBasedDriver.php
Normal file
54
lib/Doctrine/ORM/Mapping/Driver/ReflectionBasedDriver.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use ReflectionProperty;
|
||||
|
||||
/** @internal */
|
||||
trait ReflectionBasedDriver
|
||||
{
|
||||
/** @var bool */
|
||||
private $reportFieldsWhereDeclared = false;
|
||||
|
||||
/**
|
||||
* Helps to deal with the case that reflection may report properties inherited from parent classes.
|
||||
* When we know about the fields already (inheritance has been anticipated in ClassMetadataFactory),
|
||||
* the driver must skip them.
|
||||
*
|
||||
* The declaring classes may mismatch when there are private properties: The same property name may be
|
||||
* reported multiple times, but since it is private, it is in fact multiple (different) properties in
|
||||
* different classes. In that case, report the property as an individual field. (ClassMetadataFactory will
|
||||
* probably fail in that case, though.)
|
||||
*/
|
||||
private function isRepeatedPropertyDeclaration(ReflectionProperty $property, ClassMetadata $metadata): bool
|
||||
{
|
||||
if (! $this->reportFieldsWhereDeclared) {
|
||||
return $metadata->isMappedSuperclass && ! $property->isPrivate()
|
||||
|| $metadata->isInheritedField($property->name)
|
||||
|| $metadata->isInheritedAssociation($property->name)
|
||||
|| $metadata->isInheritedEmbeddedClass($property->name);
|
||||
}
|
||||
|
||||
$declaringClass = $property->class;
|
||||
|
||||
if (
|
||||
isset($metadata->fieldMappings[$property->name]['declared'])
|
||||
&& $metadata->fieldMappings[$property->name]['declared'] === $declaringClass
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
isset($metadata->associationMappings[$property->name]['declared'])
|
||||
&& $metadata->associationMappings[$property->name]['declared'] === $declaringClass
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isset($metadata->embeddedClasses[$property->name]['declared'])
|
||||
&& $metadata->embeddedClasses[$property->name]['declared'] === $declaringClass;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user