mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 15:02:22 +01:00
Compare commits
215 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8b02fd70f | ||
|
|
60adc6b7d9 | ||
|
|
c65ff6651c | ||
|
|
5f29fcdea2 | ||
|
|
2b8ac15813 | ||
|
|
6dd07e4c76 | ||
|
|
0d043059b9 | ||
|
|
bb3ce7e802 | ||
|
|
bc7e252f00 | ||
|
|
498da2ff98 | ||
|
|
73e1e42ab5 | ||
|
|
5d11648767 | ||
|
|
0ecac1b255 | ||
|
|
b2a4fac40b | ||
|
|
beeba93a53 | ||
|
|
4c253f2403 | ||
|
|
46ec86557e | ||
|
|
f287b74470 | ||
|
|
12d086551e | ||
|
|
5283e1441c | ||
|
|
18be6d2218 | ||
|
|
2fda625dba | ||
|
|
35c44a5667 | ||
|
|
0215b6b9fb | ||
|
|
cc9272f53f | ||
|
|
e3e7f3c209 | ||
|
|
c9870a3d82 | ||
|
|
827cb0c10b | ||
|
|
4d19c0ea71 | ||
|
|
17cfb944f2 | ||
|
|
78d08584f1 | ||
|
|
f7e202f3ed | ||
|
|
33f4db8405 | ||
|
|
fa63a395cc | ||
|
|
2ec2c585b0 | ||
|
|
c8025dc4f8 | ||
|
|
cd95b2a9e5 | ||
|
|
8bfe20073b | ||
|
|
38a9a1c795 | ||
|
|
2ebe18a822 | ||
|
|
9b37541b3b | ||
|
|
518d7f2ef1 | ||
|
|
7684cea8ef | ||
|
|
5085dbe94b | ||
|
|
6c64bc6067 | ||
|
|
f5246bdedd | ||
|
|
705dc6fbda | ||
|
|
faedb90ffa | ||
|
|
2da28703e3 | ||
|
|
20cec8ed79 | ||
|
|
c125a856d0 | ||
|
|
d7db596cb4 | ||
|
|
3a9aa5b8c6 | ||
|
|
99d9c46bde | ||
|
|
61d405162f | ||
|
|
b0f15e070d | ||
|
|
fbb7e24594 | ||
|
|
888a4a8eff | ||
|
|
48b4f63f61 | ||
|
|
4a62b661a5 | ||
|
|
ab4844b82a | ||
|
|
00989d6671 | ||
|
|
7ed0db0621 | ||
|
|
d6dcfbd6f7 | ||
|
|
baf6a394a1 | ||
|
|
1538d70bb9 | ||
|
|
291765e879 | ||
|
|
f79ec43e70 | ||
|
|
306b5f9812 | ||
|
|
68405f3e5b | ||
|
|
83c1ad2f57 | ||
|
|
79447cbb18 | ||
|
|
eea53397c5 | ||
|
|
3295ccfa25 | ||
|
|
b1419ddc6c | ||
|
|
0ef08c5dfb | ||
|
|
dc8ddfd3e6 | ||
|
|
278bf194ca | ||
|
|
b9f2488c6c | ||
|
|
b931a59ebc | ||
|
|
d15eef9051 | ||
|
|
c05e1709e9 | ||
|
|
6e31758c7b | ||
|
|
eff540a996 | ||
|
|
33d74e2e48 | ||
|
|
09ff36cda0 | ||
|
|
e30426cbc0 | ||
|
|
e9135b86e0 | ||
|
|
5ccb59fa02 | ||
|
|
2e927970ca | ||
|
|
0366a5796f | ||
|
|
93f7e78a14 | ||
|
|
d99e64c05e | ||
|
|
9efeefb913 | ||
|
|
3f8430459c | ||
|
|
5f12b8f7de | ||
|
|
f949b9d212 | ||
|
|
2bc0be6fa9 | ||
|
|
3dc5581294 | ||
|
|
7bf2c4c8d1 | ||
|
|
c81776ad12 | ||
|
|
d9c6f86627 | ||
|
|
ddede4064c | ||
|
|
67d82cdf72 | ||
|
|
744f0b5983 | ||
|
|
1d02289481 | ||
|
|
4bd0f974ab | ||
|
|
d0c582ca48 | ||
|
|
cc6cc26f18 | ||
|
|
768e2f3816 | ||
|
|
deb5f49413 | ||
|
|
52ce39f595 | ||
|
|
f84ecb2842 | ||
|
|
b2fedaef9e | ||
|
|
21976471a3 | ||
|
|
6fb88e1496 | ||
|
|
3ac5f119aa | ||
|
|
01fb82b497 | ||
|
|
4f1072e1ac | ||
|
|
a559563682 | ||
|
|
0f9cc194ae | ||
|
|
2513a1e2b1 | ||
|
|
4230214ced | ||
|
|
fb1f258736 | ||
|
|
aae8b43622 | ||
|
|
e66fbc434d | ||
|
|
3f4e9e397a | ||
|
|
0f6f752887 | ||
|
|
c1dd1cfc2c | ||
|
|
3684d236f6 | ||
|
|
bba6c696f5 | ||
|
|
e02e6f481b | ||
|
|
48e4e333c7 | ||
|
|
507bc514ce | ||
|
|
1ae5de5409 | ||
|
|
82508956fe | ||
|
|
a131878814 | ||
|
|
1f63389065 | ||
|
|
359dd4ecfb | ||
|
|
a0697c9aff | ||
|
|
5601c2ce4b | ||
|
|
1141fe106f | ||
|
|
8f7701279d | ||
|
|
779f9c36fa | ||
|
|
0908f92629 | ||
|
|
24badd60fb | ||
|
|
f2d794f8bc | ||
|
|
7311f77dfe | ||
|
|
16afa45abf | ||
|
|
8b4d25e94f | ||
|
|
70087782e8 | ||
|
|
dbc5a818e0 | ||
|
|
31a9c9c49b | ||
|
|
125afb8e39 | ||
|
|
45e196eb57 | ||
|
|
2c30fe6e5b | ||
|
|
6757bdf8c6 | ||
|
|
eed20ff4dd | ||
|
|
636712a928 | ||
|
|
0aa91c7140 | ||
|
|
c2f3831b85 | ||
|
|
2af52f6a18 | ||
|
|
0a79ddf344 | ||
|
|
165c8bd6dd | ||
|
|
07ee555279 | ||
|
|
e6bda4afda | ||
|
|
51b4e02873 | ||
|
|
1915dcd1e8 | ||
|
|
480d99b107 | ||
|
|
c6661caaed | ||
|
|
9e27370f15 | ||
|
|
1a3fbcb145 | ||
|
|
c950e72628 | ||
|
|
05560f260c | ||
|
|
8291a7f09b | ||
|
|
d7d6b9d2c7 | ||
|
|
26e274e373 | ||
|
|
a02642e3e6 | ||
|
|
5209184a60 | ||
|
|
b4da0ece41 | ||
|
|
3980d58b80 | ||
|
|
10cbb24649 | ||
|
|
23f54885bc | ||
|
|
7f29b576d8 | ||
|
|
a8425a5248 | ||
|
|
86ce0e5e35 | ||
|
|
39fd5f4d46 | ||
|
|
476a02075f | ||
|
|
98e10906f8 | ||
|
|
7241b4d2e0 | ||
|
|
b8db858784 | ||
|
|
a9309d748b | ||
|
|
fe09af6df1 | ||
|
|
ed50e3d967 | ||
|
|
1d59e46245 | ||
|
|
d8f3198ef8 | ||
|
|
a0a0b0e476 | ||
|
|
0078a67786 | ||
|
|
38d1124be9 | ||
|
|
e9d3c218ef | ||
|
|
6d2ca8fe40 | ||
|
|
a06011daf3 | ||
|
|
825e9641fd | ||
|
|
0846b8b102 | ||
|
|
1dd2b44982 | ||
|
|
5fbe5ebef4 | ||
|
|
d9508e97df | ||
|
|
534ed9c3c2 | ||
|
|
f4585b954f | ||
|
|
ab3a255440 | ||
|
|
a552df66a9 | ||
|
|
85238d4d98 | ||
|
|
b7e9dd023c | ||
|
|
1ac05f5e4e | ||
|
|
2e4a872272 |
@@ -12,21 +12,33 @@
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.12",
|
||||
"branchName": "2.12.x",
|
||||
"slug": "2.12",
|
||||
"name": "2.14",
|
||||
"branchName": "2.14.x",
|
||||
"slug": "2.14",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.11",
|
||||
"branchName": "2.11.x",
|
||||
"slug": "2.11",
|
||||
"name": "2.13",
|
||||
"branchName": "2.13.x",
|
||||
"slug": "2.13",
|
||||
"current": true,
|
||||
"aliases": [
|
||||
"current",
|
||||
"stable"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "2.12",
|
||||
"branchName": "2.12.x",
|
||||
"slug": "2.12",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.11",
|
||||
"branchName": "2.11.x",
|
||||
"slug": "2.11",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.10",
|
||||
"branchName": "2.10.x",
|
||||
|
||||
5
.gitattributes
vendored
5
.gitattributes
vendored
@@ -1,7 +1,8 @@
|
||||
/.github export-ignore
|
||||
/ci export-ignore
|
||||
/docs export-ignore
|
||||
/tests export-ignore
|
||||
/tools export-ignore
|
||||
/docs export-ignore
|
||||
/.github export-ignore
|
||||
.doctrine-project.json export-ignore
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
|
||||
4
.github/workflows/coding-standard.yml
vendored
4
.github/workflows/coding-standard.yml
vendored
@@ -10,6 +10,4 @@ on:
|
||||
|
||||
jobs:
|
||||
coding-standards:
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@1.4.1"
|
||||
with:
|
||||
php-version: "8.1"
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@2.0.0"
|
||||
|
||||
41
.github/workflows/continuous-integration.yml
vendored
41
.github/workflows/continuous-integration.yml
vendored
@@ -14,7 +14,7 @@ env:
|
||||
jobs:
|
||||
phpunit-smoke-check:
|
||||
name: "PHPUnit with SQLite"
|
||||
runs-on: "ubuntu-20.04"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -31,6 +31,8 @@ jobs:
|
||||
dbal-version: "2.13"
|
||||
- php-version: "8.1"
|
||||
dbal-version: "3@dev"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "3@dev"
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
@@ -52,6 +54,8 @@ jobs:
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite.xml --coverage-clover=coverage-no-cache.xml"
|
||||
@@ -72,7 +76,7 @@ jobs:
|
||||
|
||||
phpunit-postgres:
|
||||
name: "PHPUnit with PostgreSQL"
|
||||
runs-on: "ubuntu-20.04"
|
||||
runs-on: "ubuntu-22.04"
|
||||
needs: "phpunit-smoke-check"
|
||||
|
||||
strategy:
|
||||
@@ -88,6 +92,9 @@ jobs:
|
||||
- php-version: "8.0"
|
||||
dbal-version: "2.13"
|
||||
postgres-version: "14"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "3@dev"
|
||||
postgres-version: "14"
|
||||
|
||||
services:
|
||||
postgres:
|
||||
@@ -120,6 +127,8 @@ jobs:
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
|
||||
@@ -133,7 +142,7 @@ jobs:
|
||||
|
||||
phpunit-mariadb:
|
||||
name: "PHPUnit with MariaDB"
|
||||
runs-on: "ubuntu-20.04"
|
||||
runs-on: "ubuntu-22.04"
|
||||
needs: "phpunit-smoke-check"
|
||||
|
||||
strategy:
|
||||
@@ -152,6 +161,14 @@ jobs:
|
||||
dbal-version: "2.13"
|
||||
mariadb-version: "10.6"
|
||||
extension: "pdo_mysql"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "3@dev"
|
||||
mariadb-version: "10.6"
|
||||
extension: "pdo_mysql"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "3@dev"
|
||||
mariadb-version: "10.6"
|
||||
extension: "mysqli"
|
||||
|
||||
services:
|
||||
mariadb:
|
||||
@@ -186,6 +203,8 @@ jobs:
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
|
||||
@@ -199,7 +218,7 @@ jobs:
|
||||
|
||||
phpunit-mysql:
|
||||
name: "PHPUnit with MySQL"
|
||||
runs-on: "ubuntu-20.04"
|
||||
runs-on: "ubuntu-22.04"
|
||||
needs: "phpunit-smoke-check"
|
||||
|
||||
strategy:
|
||||
@@ -219,6 +238,14 @@ jobs:
|
||||
dbal-version: "2.13"
|
||||
mysql-version: "8.0"
|
||||
extension: "pdo_mysql"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "3@dev"
|
||||
mysql-version: "8.0"
|
||||
extension: "mysqli"
|
||||
- php-version: "8.2"
|
||||
dbal-version: "3@dev"
|
||||
mysql-version: "8.0"
|
||||
extension: "pdo_mysql"
|
||||
|
||||
services:
|
||||
mysql:
|
||||
@@ -252,6 +279,8 @@ jobs:
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v1"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
- name: "Run PHPUnit"
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage-no-cache.xml"
|
||||
@@ -272,7 +301,7 @@ jobs:
|
||||
|
||||
phpunit-lower-php-versions:
|
||||
name: "PHPUnit with SQLite"
|
||||
runs-on: "ubuntu-20.04"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -305,7 +334,7 @@ jobs:
|
||||
|
||||
upload_coverage:
|
||||
name: "Upload coverage to Codecov"
|
||||
runs-on: "ubuntu-20.04"
|
||||
runs-on: "ubuntu-22.04"
|
||||
needs:
|
||||
- "phpunit-smoke-check"
|
||||
- "phpunit-postgres"
|
||||
|
||||
2
.github/workflows/phpbench.yml
vendored
2
.github/workflows/phpbench.yml
vendored
@@ -15,7 +15,7 @@ env:
|
||||
jobs:
|
||||
phpbench:
|
||||
name: "PHPBench"
|
||||
runs-on: "ubuntu-20.04"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@1.4.1"
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@2.0.0"
|
||||
secrets:
|
||||
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
|
||||
4
.github/workflows/static-analysis.yml
vendored
4
.github/workflows/static-analysis.yml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
jobs:
|
||||
static-analysis-phpstan:
|
||||
name: "Static Analysis with PHPStan"
|
||||
runs-on: "ubuntu-20.04"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
|
||||
static-analysis-psalm:
|
||||
name: "Static Analysis with Psalm"
|
||||
runs-on: "ubuntu-20.04"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
24
README.md
24
README.md
@@ -1,11 +1,11 @@
|
||||
| [3.0.x][3.0] | [2.12.x][2.12] | [2.11.x][2.11] |
|
||||
| [3.0.x][3.0] | [2.14.x][2.14] | [2.13.x][2.13] |
|
||||
|:----------------:|:----------------:|:----------:|
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.12 image]][2.12] | [![Build status][2.11 image]][2.11] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.12 coverage image]][2.12 coverage] | [![Coverage Status][2.11 coverage image]][2.11 coverage] |
|
||||
| [![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] |
|
||||
|
||||
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
|
||||
|
||||
Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence
|
||||
Doctrine ORM is an object-relational mapper for PHP 7.1+ that provides transparent persistence
|
||||
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
|
||||
is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL),
|
||||
inspired by Hibernate's HQL. This provides developers with a powerful alternative to SQL that maintains flexibility
|
||||
@@ -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.12 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.12.x
|
||||
[2.12]: https://github.com/doctrine/orm/tree/2.12.x
|
||||
[2.12 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.12.x/graph/badge.svg
|
||||
[2.12 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.12.x
|
||||
[2.11 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.11.x
|
||||
[2.11]: https://github.com/doctrine/orm/tree/2.11.x
|
||||
[2.11 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.11.x/graph/badge.svg
|
||||
[2.11 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.11.x
|
||||
[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
|
||||
|
||||
218
UPGRADE.md
218
UPGRADE.md
@@ -1,3 +1,216 @@
|
||||
# Upgrade to 2.13
|
||||
|
||||
## Deprecated `QueryBuilder` methods and constants.
|
||||
|
||||
1. The `QueryBuilder::getState()` method has been deprecated as the builder state is an internal concern.
|
||||
2. Relying on the type of the query being built by using `QueryBuilder::getType()` has been deprecated.
|
||||
If necessary, track the type of the query being built outside of the builder.
|
||||
|
||||
The following `QueryBuilder` constants related to the above methods have been deprecated:
|
||||
|
||||
1. `SELECT`,
|
||||
2. `DELETE`,
|
||||
3. `UPDATE`,
|
||||
4. `STATE_DIRTY`,
|
||||
5. `STATE_CLEAN`.
|
||||
|
||||
## Deprecated omitting only the alias argument for `QueryBuilder::update` and `QueryBuilder::delete`
|
||||
|
||||
When building an UPDATE or DELETE query and when passing a class/type to the function, the alias argument must not be omitted.
|
||||
|
||||
### Before
|
||||
|
||||
```php
|
||||
$qb = $em->createQueryBuilder()
|
||||
->delete('User u')
|
||||
->where('u.id = :user_id')
|
||||
->setParameter('user_id', 1);
|
||||
```
|
||||
|
||||
### After
|
||||
|
||||
```php
|
||||
$qb = $em->createQueryBuilder()
|
||||
->delete('User', 'u')
|
||||
->where('u.id = :user_id')
|
||||
->setParameter('user_id', 1);
|
||||
```
|
||||
|
||||
## Deprecated using the `IDENTITY` identifier strategy on platform that do not support identity columns
|
||||
|
||||
If identity columns are emulated with sequences on the platform you are using,
|
||||
you should switch to the `SEQUENCE` strategy.
|
||||
|
||||
## Deprecated passing `null` to `Doctrine\ORM\Query::setFirstResult()`
|
||||
|
||||
`$query->setFirstResult(null);` is equivalent to `$query->setFirstResult(0)`.
|
||||
|
||||
## Deprecated calling setters without arguments
|
||||
|
||||
The following methods will require an argument in 3.0. Pass `null` instead of
|
||||
omitting the argument.
|
||||
|
||||
* `Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs::setFoundMetadata()`
|
||||
* `Doctrine\ORM\AbstractQuery::setHydrationCacheProfile()`
|
||||
* `Doctrine\ORM\AbstractQuery::setResultCache()`
|
||||
* `Doctrine\ORM\AbstractQuery::setResultCacheProfile()`
|
||||
|
||||
## Deprecated passing invalid fetch modes to `AbstractQuery::setFetchMode()`
|
||||
|
||||
Calling `AbstractQuery::setFetchMode()` with anything else than
|
||||
`Doctrine\ORM\Mapping::FETCH_EAGER` results in
|
||||
`Doctrine\ORM\Mapping::FETCH_LAZY` being used. Relying on that behavior is
|
||||
deprecated and will result in an exception in 3.0.
|
||||
|
||||
## Deprecated `getEntityManager()` in `Doctrine\ORM\Event\OnClearEventArgs` and `Doctrine\ORM\Event\*FlushEventArgs`
|
||||
|
||||
This method has been deprecated in:
|
||||
|
||||
* `Doctrine\ORM\Event\OnClearEventArgs`
|
||||
* `Doctrine\ORM\Event\OnFlushEventArgs`
|
||||
* `Doctrine\ORM\Event\PostFlushEventArgs`
|
||||
* `Doctrine\ORM\Event\PreFlushEventArgs`
|
||||
|
||||
It will be removed in 3.0. Use `getObjectManager()` instead.
|
||||
|
||||
## Prepare split of output walkers and tree walkers
|
||||
|
||||
In 3.0, `SqlWalker` and its child classes won't implement the `TreeWalker`
|
||||
interface anymore. Relying on that inheritance is deprecated.
|
||||
|
||||
The following methods of the `TreeWalker` interface have been deprecated:
|
||||
|
||||
* `setQueryComponent()`
|
||||
* `walkSelectClause()`
|
||||
* `walkFromClause()`
|
||||
* `walkFunction()`
|
||||
* `walkOrderByClause()`
|
||||
* `walkOrderByItem()`
|
||||
* `walkHavingClause()`
|
||||
* `walkJoin()`
|
||||
* `walkSelectExpression()`
|
||||
* `walkQuantifiedExpression()`
|
||||
* `walkSubselect()`
|
||||
* `walkSubselectFromClause()`
|
||||
* `walkSimpleSelectClause()`
|
||||
* `walkSimpleSelectExpression()`
|
||||
* `walkAggregateExpression()`
|
||||
* `walkGroupByClause()`
|
||||
* `walkGroupByItem()`
|
||||
* `walkDeleteClause()`
|
||||
* `walkUpdateClause()`
|
||||
* `walkUpdateItem()`
|
||||
* `walkWhereClause()`
|
||||
* `walkConditionalExpression()`
|
||||
* `walkConditionalTerm()`
|
||||
* `walkConditionalFactor()`
|
||||
* `walkConditionalPrimary()`
|
||||
* `walkExistsExpression()`
|
||||
* `walkCollectionMemberExpression()`
|
||||
* `walkEmptyCollectionComparisonExpression()`
|
||||
* `walkNullComparisonExpression()`
|
||||
* `walkInExpression()`
|
||||
* `walkInstanceOfExpression()`
|
||||
* `walkLiteral()`
|
||||
* `walkBetweenExpression()`
|
||||
* `walkLikeExpression()`
|
||||
* `walkStateFieldPathExpression()`
|
||||
* `walkComparisonExpression()`
|
||||
* `walkInputParameter()`
|
||||
* `walkArithmeticExpression()`
|
||||
* `walkArithmeticTerm()`
|
||||
* `walkStringPrimary()`
|
||||
* `walkArithmeticFactor()`
|
||||
* `walkSimpleArithmeticExpression()`
|
||||
* `walkPathExpression()`
|
||||
* `walkResultVariable()`
|
||||
* `getExecutor()`
|
||||
|
||||
The following changes have been made to the abstract `TreeWalkerAdapter` class:
|
||||
|
||||
* All implementations of now-deprecated `TreeWalker` methods have been
|
||||
deprecated as well.
|
||||
* The method `setQueryComponent()` will become protected in 3.0. Calling it
|
||||
publicly is deprecated.
|
||||
* The method `_getQueryComponents()` is deprecated, call `getQueryComponents()`
|
||||
instead.
|
||||
|
||||
On the `TreeWalkerChain` class, all implementations of now-deprecated
|
||||
`TreeWalker` methods have been deprecated as well. However, `SqlWalker` is
|
||||
unaffected by those deprecations and will continue to implement all of those
|
||||
methods.
|
||||
|
||||
## Deprecated passing `null` to `Doctrine\ORM\Query::setDQL()`
|
||||
|
||||
Doing `$query->setDQL(null);` achieves nothing.
|
||||
|
||||
## Deprecated omitting second argument to `NamingStrategy::joinColumnName`
|
||||
|
||||
When implementing `NamingStrategy`, it is deprecated to implement
|
||||
`joinColumnName()` with only one argument.
|
||||
|
||||
### Before
|
||||
|
||||
```php
|
||||
<?php
|
||||
class MyStrategy implements NamingStrategy
|
||||
{
|
||||
/**
|
||||
* @param string $propertyName A property name.
|
||||
*/
|
||||
public function joinColumnName($propertyName): string
|
||||
{
|
||||
// …
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### After
|
||||
|
||||
For backward-compatibility reasons, the parameter has to be optional, but can
|
||||
be documented as guaranteed to be a `class-string`.
|
||||
|
||||
```php
|
||||
<?php
|
||||
class MyStrategy implements NamingStrategy
|
||||
{
|
||||
/**
|
||||
* @param string $propertyName A property name.
|
||||
* @param class-string $className
|
||||
*/
|
||||
public function joinColumnName($propertyName, $className = null): string
|
||||
{
|
||||
// …
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Deprecated methods related to named queries
|
||||
|
||||
The following methods have been deprecated:
|
||||
|
||||
- `Doctrine\ORM\Query\ResultSetMappingBuilder::addNamedNativeQueryMapping()`
|
||||
- `Doctrine\ORM\Query\ResultSetMappingBuilder::addNamedNativeQueryResultClassMapping()`
|
||||
- `Doctrine\ORM\Query\ResultSetMappingBuilder::addNamedNativQueryResultSetMapping()`
|
||||
- `Doctrine\ORM\Query\ResultSetMappingBuilder::addNamedNativQueryEntityResultMapping()`
|
||||
|
||||
## Deprecated classes related to Doctrine 1 and reverse engineering
|
||||
|
||||
The following classes have been deprecated:
|
||||
|
||||
- `Doctrine\ORM\Tools\ConvertDoctrine1Schema`
|
||||
- `Doctrine\ORM\Tools\DisconnectedClassMetadataFactory`
|
||||
|
||||
## Deprecate `ClassMetadataInfo` usage
|
||||
|
||||
It is deprecated to pass `Doctrine\ORM\Mapping\ClassMetadataInfo` instances
|
||||
that are not also instances of `Doctrine\ORM\ClassMetadata` to the following
|
||||
methods:
|
||||
|
||||
- `Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder::__construct()`
|
||||
- `Doctrine\ORM\Mapping\Driver\DatabaseDriver::loadMetadataForClass()`
|
||||
- `Doctrine\ORM\Tools\SchemaValidator::validateClass()`
|
||||
|
||||
# Upgrade to 2.12
|
||||
|
||||
## Deprecated the `doctrine` binary.
|
||||
@@ -41,11 +254,6 @@ This is now deprecated. Please extend `EntityRepository` instead.
|
||||
+$entityManager->getRepository(CmsUser::class);
|
||||
```
|
||||
|
||||
## BC Break: `AttributeDriver` and `AnnotationDriver` no longer extends parent class from `doctrine/persistence`
|
||||
|
||||
Both these classes used to extend an abstract `AnnotationDriver` class defined
|
||||
in `doctrine/persistence`, and no longer do.
|
||||
|
||||
## Deprecate `AttributeDriver::getReader()` and `AnnotationDriver::getReader()`
|
||||
|
||||
That method was inherited from the abstract `AnnotationDriver` class of
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"doctrine/collections": "^1.5",
|
||||
"doctrine/common": "^3.0.3",
|
||||
"doctrine/dbal": "^2.13.1 || ^3.2",
|
||||
"doctrine/deprecations": "^0.5.3",
|
||||
"doctrine/deprecations": "^0.5.3 || ^1",
|
||||
"doctrine/event-manager": "^1.1",
|
||||
"doctrine/inflector": "^1.4 || ^2.0",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
@@ -40,20 +40,21 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/annotations": "^1.13",
|
||||
"doctrine/coding-standard": "^9.0",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^10.0",
|
||||
"phpbench/phpbench": "^0.16.10 || ^1.0",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.5.0",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.8.5",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.6.2",
|
||||
"squizlabs/php_codesniffer": "3.7.1",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
|
||||
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
|
||||
"vimeo/psalm": "4.22.0"
|
||||
"vimeo/psalm": "4.27.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/annotations": "<1.13 || >= 2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Provides support for XSD validation for XML mapping files",
|
||||
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0",
|
||||
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
|
||||
},
|
||||
|
||||
@@ -47,7 +47,7 @@ appropriate autoloaders.
|
||||
}
|
||||
|
||||
foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) {
|
||||
if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadataInfo::MANY_TO_MANY && $mapping['isOwningSide']) {
|
||||
if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadata::MANY_TO_MANY && $mapping['isOwningSide']) {
|
||||
$mappedTableName = $mapping['joinTable']['name'];
|
||||
$classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName;
|
||||
}
|
||||
|
||||
@@ -87,12 +87,12 @@ Such an interface could look like this:
|
||||
* @return \Zend_View_Helper_Interface
|
||||
*/
|
||||
public function setView(\Zend_View_Interface $view);
|
||||
|
||||
|
||||
/**
|
||||
* @return \Zend_View_Interface
|
||||
*/
|
||||
public function getView();
|
||||
|
||||
|
||||
/**
|
||||
* Renders this strategy. This method will be called when the user
|
||||
* displays the site.
|
||||
@@ -100,7 +100,7 @@ Such an interface could look like this:
|
||||
* @return string
|
||||
*/
|
||||
public function renderFrontend();
|
||||
|
||||
|
||||
/**
|
||||
* Renders the backend of this block. This method will be called when
|
||||
* a user tries to reconfigure this block instance.
|
||||
@@ -118,21 +118,21 @@ Such an interface could look like this:
|
||||
* @return array
|
||||
*/
|
||||
public function getRequiredPanelTypes();
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether a Block is able to use a given type or not
|
||||
* @param string $typeName The typename
|
||||
* @return boolean
|
||||
*/
|
||||
public function canUsePanelType($typeName);
|
||||
|
||||
|
||||
public function setBlockEntity(AbstractBlock $block);
|
||||
|
||||
public function getBlockEntity();
|
||||
}
|
||||
|
||||
|
||||
As you can see, we have a method "setBlockEntity" which ties a potential strategy to an object of type AbstractBlock. This type will simply define the basic behaviour of our blocks and could potentially look something like this:
|
||||
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
@@ -177,7 +177,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
|
||||
public function getStrategyClassName() {
|
||||
return $this->strategyClassName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the instantiated strategy
|
||||
*
|
||||
@@ -186,7 +186,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
|
||||
public function getStrategyInstance() {
|
||||
return $this->strategyInstance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the strategy this block / panel should work as. Make sure that you've used
|
||||
* this method before persisting the block!
|
||||
@@ -213,28 +213,29 @@ This might look like this:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use \Doctrine\ORM,
|
||||
\Doctrine\Common;
|
||||
|
||||
use Doctrine\Common\EventSubscriber;
|
||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Events;
|
||||
|
||||
/**
|
||||
* The BlockStrategyEventListener will initialize a strategy after the
|
||||
* block itself was loaded.
|
||||
*/
|
||||
class BlockStrategyEventListener implements Common\EventSubscriber {
|
||||
|
||||
class BlockStrategyEventListener implements EventSubscriber {
|
||||
|
||||
protected $view;
|
||||
|
||||
|
||||
public function __construct(\Zend_View_Interface $view) {
|
||||
$this->view = $view;
|
||||
}
|
||||
|
||||
|
||||
public function getSubscribedEvents() {
|
||||
return array(ORM\Events::postLoad);
|
||||
return array(Events::postLoad);
|
||||
}
|
||||
|
||||
public function postLoad(ORM\Event\LifecycleEventArgs $args) {
|
||||
$blockItem = $args->getEntity();
|
||||
|
||||
|
||||
public function postLoad(LifecycleEventArgs $args) {
|
||||
$blockItem = $args->getObject();
|
||||
|
||||
// Both blocks and panels are instances of Block\AbstractBlock
|
||||
if ($blockItem instanceof Block\AbstractBlock) {
|
||||
$strategy = $blockItem->getStrategyClassName();
|
||||
|
||||
@@ -207,6 +207,8 @@ Optional parameters:
|
||||
- ``comment``: The comment of the column in the schema (might not
|
||||
be supported by all vendors).
|
||||
|
||||
- ``charset``: The charset of the column (only supported by Mysql, PostgreSQL, Sqlite and SQLServer).
|
||||
|
||||
- ``collation``: The collation of the column (only supported by Mysql, PostgreSQL, Sqlite and SQLServer).
|
||||
|
||||
- ``check``: Adds a check constraint type to the column (might not
|
||||
@@ -681,6 +683,8 @@ Optional parameters:
|
||||
"columnDefinition" attribute on :ref:`#[Column] <attrref_column>` also sets
|
||||
the related ``#[JoinColumn]``'s columnDefinition. This is necessary to
|
||||
make foreign keys work.
|
||||
- **options**:
|
||||
See "options" attribute on :ref:`#[Column] <attrref_column>`.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -79,7 +79,9 @@ array of events it should be subscribed to.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class TestEventSubscriber implements \Doctrine\Common\EventSubscriber
|
||||
use Doctrine\Common\EventSubscriber;
|
||||
|
||||
class TestEventSubscriber implements EventSubscriber
|
||||
{
|
||||
public $preFooInvoked = false;
|
||||
|
||||
@@ -211,9 +213,8 @@ specific to a particular entity class's lifecycle.
|
||||
.. code-block:: attribute
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||
|
||||
#[Entity]
|
||||
#[HasLifecycleCallbacks]
|
||||
@@ -245,7 +246,6 @@ specific to a particular entity class's lifecycle.
|
||||
.. code-block:: annotation
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
|
||||
/**
|
||||
@@ -504,7 +504,6 @@ result in an infinite loop.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\ORM\Event\PreFlushEventArgs;
|
||||
|
||||
class PreFlushExampleListener
|
||||
@@ -542,7 +541,7 @@ mentioned sets. See this example:
|
||||
{
|
||||
public function onFlush(OnFlushEventArgs $eventArgs)
|
||||
{
|
||||
$em = $eventArgs->getEntityManager();
|
||||
$em = $eventArgs->getObjectManager();
|
||||
$uow = $em->getUnitOfWork();
|
||||
|
||||
foreach ($uow->getScheduledEntityInsertions() as $entity) {
|
||||
@@ -590,7 +589,6 @@ This event is not a lifecycle callback.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\ORM\Event\PostFlushEventArgs;
|
||||
|
||||
class PostFlushExampleListener
|
||||
@@ -615,7 +613,7 @@ Changes to associations of the updated entity are never allowed in
|
||||
this event, since Doctrine cannot guarantee to correctly handle
|
||||
referential integrity at this point of the flush operation. This
|
||||
event has a powerful feature however, it is executed with a
|
||||
`_PreUpdateEventArgs`_ instance, which contains a reference to the
|
||||
`PreUpdateEventArgs`_ instance, which contains a reference to the
|
||||
computed change-set of this entity.
|
||||
|
||||
This means you have access to all the fields that have changed for
|
||||
@@ -637,6 +635,8 @@ A simple example for this event looks like:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
class NeverAliceOnlyBobListener
|
||||
{
|
||||
public function preUpdate(PreUpdateEventArgs $eventArgs)
|
||||
@@ -644,6 +644,9 @@ A simple example for this event looks like:
|
||||
if ($eventArgs->getEntity() instanceof User) {
|
||||
if ($eventArgs->hasChangedField('name') && $eventArgs->getNewValue('name') == 'Alice') {
|
||||
$eventArgs->setNewValue('name', 'Bob');
|
||||
// The following will only work if `status` is already present in the computed changeset.
|
||||
// Otherwise it will throw an InvalidArgumentException:
|
||||
$eventArgs->setNewValue('status', 'active');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,6 +659,8 @@ lifecycle callback when there are expensive validations to call:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
class ValidCreditCardListener
|
||||
{
|
||||
public function preUpdate(PreUpdateEventArgs $eventArgs)
|
||||
@@ -751,7 +756,7 @@ An entity listener is a lifecycle listener class used for an entity.
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: attribute
|
||||
|
||||
|
||||
<?php
|
||||
namespace MyProject\Entity;
|
||||
use App\EventListener\UserListener;
|
||||
@@ -807,6 +812,8 @@ An ``Entity Listener`` could be any class, by default it should be a class with
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
class UserListener
|
||||
{
|
||||
public function preUpdate(User $user, PreUpdateEventArgs $event)
|
||||
@@ -823,6 +830,10 @@ you need to map the listener method using the event type mapping:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
use Doctrine\ORM\Event\PreFlushEventArgs;
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
|
||||
class UserListener
|
||||
{
|
||||
/** @PrePersist */
|
||||
@@ -907,6 +918,8 @@ Specifying an entity listener instance :
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
// User.php
|
||||
|
||||
/** @Entity @EntityListeners({"UserListener"}) */
|
||||
@@ -933,12 +946,14 @@ Specifying an entity listener instance :
|
||||
$listener = $container->get('user_listener');
|
||||
$em->getConfiguration()->getEntityListenerResolver()->register($listener);
|
||||
|
||||
Implementing your own resolver :
|
||||
Implementing your own resolver:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class MyEntityListenerResolver extends \Doctrine\ORM\Mapping\DefaultEntityListenerResolver
|
||||
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
|
||||
|
||||
class MyEntityListenerResolver extends DefaultEntityListenerResolver
|
||||
{
|
||||
public function __construct($container)
|
||||
{
|
||||
@@ -972,13 +987,15 @@ This event is not a lifecycle callback.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
|
||||
|
||||
$test = new TestEventListener();
|
||||
$evm = $em->getEventManager();
|
||||
$evm->addEventListener(Doctrine\ORM\Events::loadClassMetadata, $test);
|
||||
|
||||
class TestEventListener
|
||||
{
|
||||
public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs)
|
||||
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
|
||||
{
|
||||
$classMetadata = $eventArgs->getClassMetadata();
|
||||
$fieldMapping = array(
|
||||
@@ -1011,13 +1028,16 @@ instance and class metadata.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Tools\ToolEvents;
|
||||
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;
|
||||
|
||||
$test = new TestEventListener();
|
||||
$evm = $em->getEventManager();
|
||||
$evm->addEventListener(\Doctrine\ORM\Tools\ToolEvents::postGenerateSchemaTable, $test);
|
||||
$evm->addEventListener(ToolEvents::postGenerateSchemaTable, $test);
|
||||
|
||||
class TestEventListener
|
||||
{
|
||||
public function postGenerateSchemaTable(\Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs $eventArgs)
|
||||
public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $eventArgs)
|
||||
{
|
||||
$classMetadata = $eventArgs->getClassMetadata();
|
||||
$schema = $eventArgs->getSchema();
|
||||
@@ -1035,13 +1055,16 @@ and the EntityManager.
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\ORM\Tools\ToolEvents;
|
||||
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
|
||||
|
||||
$test = new TestEventListener();
|
||||
$evm = $em->getEventManager();
|
||||
$evm->addEventListener(\Doctrine\ORM\Tools\ToolEvents::postGenerateSchema, $test);
|
||||
$evm->addEventListener(ToolEvents::postGenerateSchema, $test);
|
||||
|
||||
class TestEventListener
|
||||
{
|
||||
public function postGenerateSchema(\Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs $eventArgs)
|
||||
public function postGenerateSchema(GenerateSchemaEventArgs $eventArgs)
|
||||
{
|
||||
$schema = $eventArgs->getSchema();
|
||||
$em = $eventArgs->getEntityManager();
|
||||
|
||||
@@ -178,9 +178,9 @@ relationships involving types that employ this mapping strategy are
|
||||
very performing.
|
||||
|
||||
There is a general performance consideration with Single Table
|
||||
Inheritance: If the target-entity of a many-to-one or one-to-one
|
||||
association is an STI entity, it is preferable for performance reasons that it
|
||||
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
|
||||
Inheritance: If the target-entity of a many-to-one or one-to-one
|
||||
association is an STI entity, it is preferable for performance reasons that it
|
||||
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
|
||||
Otherwise Doctrine *CANNOT* create proxy instances
|
||||
of this entity and will *ALWAYS* load the entity eagerly.
|
||||
|
||||
@@ -284,9 +284,9 @@ themselves on access of any subtype fields, so accessing fields of
|
||||
subtypes after such a query is not safe.
|
||||
|
||||
There is a general performance consideration with Class Table
|
||||
Inheritance: If the target-entity of a many-to-one or one-to-one
|
||||
association is a CTI entity, it is preferable for performance reasons that it
|
||||
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
|
||||
Inheritance: If the target-entity of a many-to-one or one-to-one
|
||||
association is a CTI entity, it is preferable for performance reasons that it
|
||||
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
|
||||
Otherwise Doctrine *CANNOT* create proxy instances
|
||||
of this entity and will *ALWAYS* load the entity eagerly.
|
||||
|
||||
|
||||
@@ -55,51 +55,66 @@ Implementing Metadata Drivers
|
||||
|
||||
In addition to the included metadata drivers you can very easily
|
||||
implement your own. All you need to do is define a class which
|
||||
implements the ``Driver`` interface:
|
||||
implements the ``MappingDriver`` interface:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
|
||||
interface Driver
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Persistence\Mapping\Driver;
|
||||
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
|
||||
/**
|
||||
* Contract for metadata drivers.
|
||||
*/
|
||||
interface MappingDriver
|
||||
{
|
||||
/**
|
||||
* Loads the metadata for the specified class into the provided container.
|
||||
*
|
||||
* @param string $className
|
||||
* @param ClassMetadataInfo $metadata
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
function loadMetadataForClass($className, ClassMetadataInfo $metadata);
|
||||
|
||||
public function loadMetadataForClass(string $className, ClassMetadata $metadata);
|
||||
|
||||
/**
|
||||
* Gets the names of all mapped classes known to this driver.
|
||||
*
|
||||
* @return array The names of all mapped classes known to this driver.
|
||||
*/
|
||||
function getAllClassNames();
|
||||
|
||||
/**
|
||||
* Whether the class with the specified name should have its metadata loaded.
|
||||
* This is only the case if it is either mapped as an Entity or a
|
||||
* MappedSuperclass.
|
||||
*
|
||||
* @param string $className
|
||||
* @return boolean
|
||||
* @return array<int, string> The names of all mapped classes known to this driver.
|
||||
* @psalm-return list<class-string>
|
||||
*/
|
||||
function isTransient($className);
|
||||
public function getAllClassNames();
|
||||
|
||||
/**
|
||||
* Returns whether the class with the specified name should have its metadata loaded.
|
||||
* This is only the case if it is either mapped as an Entity or a MappedSuperclass.
|
||||
*
|
||||
* @psalm-param class-string $className
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isTransient(string $className);
|
||||
}
|
||||
|
||||
If you want to write a metadata driver to parse information from
|
||||
some file format we've made your life a little easier by providing
|
||||
the ``AbstractFileDriver`` implementation for you to extend from:
|
||||
the ``FileDriver`` implementation for you to extend from:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
class MyMetadataDriver extends AbstractFileDriver
|
||||
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\Driver\FileDriver;
|
||||
|
||||
class MyMetadataDriver extends FileDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -109,11 +124,11 @@ the ``AbstractFileDriver`` implementation for you to extend from:
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
$data = $this->_loadMappingFile($file);
|
||||
|
||||
// populate ClassMetadataInfo instance from $data
|
||||
// populate ClassMetadata instance from $data
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,13 +142,12 @@ the ``AbstractFileDriver`` implementation for you to extend from:
|
||||
|
||||
.. note::
|
||||
|
||||
When using the ``AbstractFileDriver`` it requires that you
|
||||
only have one entity defined per file and the file named after the
|
||||
class described inside where namespace separators are replaced by
|
||||
periods. So if you have an entity named ``Entities\User`` and you
|
||||
wanted to write a mapping file for your driver above you would need
|
||||
to name the file ``Entities.User.dcm.ext`` for it to be
|
||||
recognized.
|
||||
When using the ``FileDriver`` it requires that you only have one
|
||||
entity defined per file and the file named after the class described
|
||||
inside where namespace separators are replaced by periods. So if you
|
||||
have an entity named ``Entities\User`` and you wanted to write a
|
||||
mapping file for your driver above you would need to name the file
|
||||
``Entities.User.dcm.ext`` for it to be recognized.
|
||||
|
||||
|
||||
Now you can use your ``MyMetadataDriver`` implementation by setting
|
||||
@@ -156,14 +170,6 @@ entity when needed.
|
||||
|
||||
You have all the methods you need to manually specify the mapping
|
||||
information instead of using some mapping file to populate it from.
|
||||
The base ``ClassMetadataInfo`` class is responsible for only data
|
||||
storage and is not meant for runtime use. It does not require that
|
||||
the class actually exists yet so it is useful for describing some
|
||||
entity before it exists and using that information to generate for
|
||||
example the entities themselves. The class ``ClassMetadata``
|
||||
extends ``ClassMetadataInfo`` and adds some functionality required
|
||||
for runtime usage and requires that the PHP class is present and
|
||||
can be autoloaded.
|
||||
|
||||
You can read more about the API of the ``ClassMetadata`` classes in
|
||||
the PHP Mapping chapter.
|
||||
|
||||
@@ -96,6 +96,8 @@ For this you just need to use the ``StaticPHPDriver``:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver;
|
||||
|
||||
$driver = new StaticPHPDriver('/path/to/entities');
|
||||
$em->getConfiguration()->setMetadataDriverImpl($driver);
|
||||
|
||||
@@ -185,13 +187,12 @@ It also has several methods that create builders (which are necessary for advanc
|
||||
- ``createManyToMany($name, $targetEntity)`` returns an ``ManyToManyAssociationBuilder`` instance
|
||||
- ``createOneToMany($name, $targetEntity)`` returns an ``OneToManyAssociationBuilder`` instance
|
||||
|
||||
ClassMetadataInfo API
|
||||
---------------------
|
||||
ClassMetadata API
|
||||
-----------------
|
||||
|
||||
The ``ClassMetadataInfo`` class is the base data object for storing
|
||||
the mapping metadata for a single entity. It contains all the
|
||||
getters and setters you need populate and retrieve information for
|
||||
an entity.
|
||||
The ``ClassMetadata`` class is the data object for storing the mapping
|
||||
metadata for a single entity. It contains all the getters and setters
|
||||
you need populate and retrieve information for an entity.
|
||||
|
||||
General Setters
|
||||
~~~~~~~~~~~~~~~
|
||||
@@ -309,13 +310,11 @@ Lifecycle Callback Getters
|
||||
- ``hasLifecycleCallbacks($lifecycleEvent)``
|
||||
- ``getLifecycleCallbacks($event)``
|
||||
|
||||
ClassMetadata API
|
||||
-----------------
|
||||
Runtime reflection methods
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``ClassMetadata`` class extends ``ClassMetadataInfo`` and adds
|
||||
the runtime functionality required by Doctrine. It adds a few extra
|
||||
methods related to runtime reflection for working with the entities
|
||||
themselves.
|
||||
These are methods related to runtime reflection for working with the
|
||||
entities themselves.
|
||||
|
||||
|
||||
- ``getReflectionClass()``
|
||||
|
||||
@@ -268,7 +268,7 @@ Doctrine\DBAL\ParameterType::* or a DBAL Type name for conversion.
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
|
||||
// prevents attempt to load metadata for date time class, improving performance
|
||||
$qb->setParameter('date', new \DateTimeImmutable(), Types::DATE_IMMUTABLE)
|
||||
$qb->setParameter('date', new \DateTimeImmutable(), Types::DATETIME_IMMUTABLE)
|
||||
|
||||
If you've got several parameters to bind to your query, you can
|
||||
also use setParameters() instead of setParameter() with the
|
||||
|
||||
@@ -149,7 +149,7 @@ When using the SchemaTool class directly, create your schema using
|
||||
the ``createSchema()`` method. First create an instance of the
|
||||
``SchemaTool`` and pass it an instance of the ``EntityManager``
|
||||
that you want to use to create the schema. This method receives an
|
||||
array of ``ClassMetadataInfo`` instances.
|
||||
array of ``ClassMetadata`` instances.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -180,8 +180,8 @@ tables of the current model to clean up with orphaned tables.
|
||||
|
||||
You can also use database introspection to update your schema
|
||||
easily with the ``updateSchema()`` method. It will compare your
|
||||
existing database schema to the passed array of
|
||||
``ClassMetadataInfo`` instances.
|
||||
existing database schema to the passed array of ``ClassMetadata``
|
||||
instances.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -324,9 +324,9 @@ convert to and the path to generate it:
|
||||
Reverse Engineering
|
||||
-------------------
|
||||
|
||||
You can use the ``DatabaseDriver`` to reverse engineer a database
|
||||
to an array of ``ClassMetadataInfo`` instances and generate YAML,
|
||||
XML, etc. from them.
|
||||
You can use the ``DatabaseDriver`` to reverse engineer a database to an
|
||||
array of ``ClassMetadata`` instances and generate YAML, XML, etc. from
|
||||
them.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ information about its type and if it's the owning or inverse side.
|
||||
{
|
||||
/** @Id @GeneratedValue @Column(type="string") */
|
||||
private $id;
|
||||
|
||||
|
||||
/**
|
||||
* Bidirectional - Many users have Many favorite comments (OWNING SIDE)
|
||||
*
|
||||
@@ -45,7 +45,7 @@ information about its type and if it's the owning or inverse side.
|
||||
* @JoinTable(name="user_favorite_comments")
|
||||
*/
|
||||
private $favorites;
|
||||
|
||||
|
||||
/**
|
||||
* Unidirectional - Many users have marked many comments as read
|
||||
*
|
||||
@@ -53,14 +53,14 @@ information about its type and if it's the owning or inverse side.
|
||||
* @JoinTable(name="user_read_comments")
|
||||
*/
|
||||
private $commentsRead;
|
||||
|
||||
|
||||
/**
|
||||
* Bidirectional - One-To-Many (INVERSE SIDE)
|
||||
*
|
||||
* @OneToMany(targetEntity="Comment", mappedBy="author")
|
||||
*/
|
||||
private $commentsAuthored;
|
||||
|
||||
|
||||
/**
|
||||
* Unidirectional - Many-To-One
|
||||
*
|
||||
@@ -68,20 +68,20 @@ information about its type and if it's the owning or inverse side.
|
||||
*/
|
||||
private $firstComment;
|
||||
}
|
||||
|
||||
|
||||
/** @Entity */
|
||||
class Comment
|
||||
{
|
||||
/** @Id @GeneratedValue @Column(type="string") */
|
||||
private $id;
|
||||
|
||||
|
||||
/**
|
||||
* Bidirectional - Many comments are favorited by many users (INVERSE SIDE)
|
||||
*
|
||||
* @ManyToMany(targetEntity="User", mappedBy="favorites")
|
||||
*/
|
||||
private $userFavorites;
|
||||
|
||||
|
||||
/**
|
||||
* Bidirectional - Many Comments are authored by one user (OWNING SIDE)
|
||||
*
|
||||
@@ -100,19 +100,19 @@ definitions omitted):
|
||||
firstComment_id VARCHAR(255) DEFAULT NULL,
|
||||
PRIMARY KEY(id)
|
||||
) ENGINE = InnoDB;
|
||||
|
||||
|
||||
CREATE TABLE Comment (
|
||||
id VARCHAR(255) NOT NULL,
|
||||
author_id VARCHAR(255) DEFAULT NULL,
|
||||
PRIMARY KEY(id)
|
||||
) ENGINE = InnoDB;
|
||||
|
||||
|
||||
CREATE TABLE user_favorite_comments (
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
favorite_comment_id VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY(user_id, favorite_comment_id)
|
||||
) ENGINE = InnoDB;
|
||||
|
||||
|
||||
CREATE TABLE user_read_comments (
|
||||
user_id VARCHAR(255) NOT NULL,
|
||||
comment_id VARCHAR(255) NOT NULL,
|
||||
@@ -135,7 +135,7 @@ relations of the ``User``:
|
||||
public function getReadComments() {
|
||||
return $this->commentsRead;
|
||||
}
|
||||
|
||||
|
||||
public function setFirstComment(Comment $c) {
|
||||
$this->firstComment = $c;
|
||||
}
|
||||
@@ -148,17 +148,17 @@ The interaction code would then look like in the following snippet
|
||||
|
||||
<?php
|
||||
$user = $em->find('User', $userId);
|
||||
|
||||
|
||||
// unidirectional many to many
|
||||
$comment = $em->find('Comment', $readCommentId);
|
||||
$user->getReadComments()->add($comment);
|
||||
|
||||
|
||||
$em->flush();
|
||||
|
||||
|
||||
// unidirectional many to one
|
||||
$myFirstComment = new Comment();
|
||||
$user->setFirstComment($myFirstComment);
|
||||
|
||||
|
||||
$em->persist($myFirstComment);
|
||||
$em->flush();
|
||||
|
||||
@@ -171,40 +171,40 @@ fields on both sides:
|
||||
class User
|
||||
{
|
||||
// ..
|
||||
|
||||
|
||||
public function getAuthoredComments() {
|
||||
return $this->commentsAuthored;
|
||||
}
|
||||
|
||||
|
||||
public function getFavoriteComments() {
|
||||
return $this->favorites;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Comment
|
||||
{
|
||||
// ...
|
||||
|
||||
|
||||
public function getUserFavorites() {
|
||||
return $this->userFavorites;
|
||||
}
|
||||
|
||||
|
||||
public function setAuthor(User $author = null) {
|
||||
$this->author = $author;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Many-to-Many
|
||||
$user->getFavorites()->add($favoriteComment);
|
||||
$favoriteComment->getUserFavorites()->add($user);
|
||||
|
||||
|
||||
$em->flush();
|
||||
|
||||
|
||||
// Many-To-One / One-To-Many Bidirectional
|
||||
$newComment = new Comment();
|
||||
$user->getAuthoredComments()->add($newComment);
|
||||
$newComment->setAuthor($user);
|
||||
|
||||
|
||||
$em->persist($newComment);
|
||||
$em->flush();
|
||||
|
||||
@@ -225,10 +225,10 @@ element. Here are some examples:
|
||||
// Remove by Elements
|
||||
$user->getComments()->removeElement($comment);
|
||||
$comment->setAuthor(null);
|
||||
|
||||
|
||||
$user->getFavorites()->removeElement($comment);
|
||||
$comment->getUserFavorites()->removeElement($user);
|
||||
|
||||
|
||||
// Remove by Key
|
||||
$user->getComments()->remove($ithComment);
|
||||
$comment->setAuthor(null);
|
||||
@@ -240,7 +240,7 @@ Notice how both sides of the bidirectional association are always
|
||||
updated. Unidirectional associations are consequently simpler to
|
||||
handle.
|
||||
|
||||
Also note that if you use type-hinting in your methods, you will
|
||||
Also note that if you use type-hinting in your methods, you will
|
||||
have to specify a nullable type, i.e. ``setAddress(?Address $address)``,
|
||||
otherwise ``setAddress(null)`` will fail to remove the association.
|
||||
Another way to deal with this is to provide a special method, like
|
||||
@@ -271,8 +271,8 @@ entities that have been re-added to the collection.
|
||||
|
||||
Say you clear a collection of tags by calling
|
||||
``$post->getTags()->clear();`` and then call
|
||||
``$post->getTags()->add($tag)``. This will not recognize the tag having
|
||||
already been added previously and will consequently issue two separate database
|
||||
``$post->getTags()->add($tag)``. This will not recognize the tag having
|
||||
already been added previously and will consequently issue two separate database
|
||||
calls.
|
||||
|
||||
Association Management Methods
|
||||
@@ -296,7 +296,7 @@ example that encapsulate much of the association management code:
|
||||
// Collections implement ArrayAccess
|
||||
$this->commentsRead[] = $comment;
|
||||
}
|
||||
|
||||
|
||||
public function addComment(Comment $comment) {
|
||||
if (count($this->commentsAuthored) == 0) {
|
||||
$this->setFirstComment($comment);
|
||||
@@ -304,30 +304,30 @@ example that encapsulate much of the association management code:
|
||||
$this->comments[] = $comment;
|
||||
$comment->setAuthor($this);
|
||||
}
|
||||
|
||||
|
||||
private function setFirstComment(Comment $c) {
|
||||
$this->firstComment = $c;
|
||||
}
|
||||
|
||||
|
||||
public function addFavorite(Comment $comment) {
|
||||
$this->favorites->add($comment);
|
||||
$comment->addUserFavorite($this);
|
||||
}
|
||||
|
||||
|
||||
public function removeFavorite(Comment $comment) {
|
||||
$this->favorites->removeElement($comment);
|
||||
$comment->removeUserFavorite($this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Comment
|
||||
{
|
||||
// ..
|
||||
|
||||
|
||||
public function addUserFavorite(User $user) {
|
||||
$this->userFavorites[] = $user;
|
||||
}
|
||||
|
||||
|
||||
public function removeUserFavorite(User $user) {
|
||||
$this->userFavorites->removeElement($user);
|
||||
}
|
||||
@@ -373,7 +373,7 @@ as your preferences.
|
||||
Synchronizing Bidirectional Collections
|
||||
---------------------------------------
|
||||
|
||||
In the case of Many-To-Many associations you as the developer have the
|
||||
In the case of Many-To-Many associations you as the developer have the
|
||||
responsibility of keeping the collections on the owning and inverse side
|
||||
in sync when you apply changes to them. Doctrine can only
|
||||
guarantee a consistent state for the hydration, not for your client
|
||||
@@ -387,7 +387,7 @@ can show the possible caveats you can encounter:
|
||||
<?php
|
||||
$user->getFavorites()->add($favoriteComment);
|
||||
// not calling $favoriteComment->getUserFavorites()->add($user);
|
||||
|
||||
|
||||
$user->getFavorites()->contains($favoriteComment); // TRUE
|
||||
$favoriteComment->getUserFavorites()->contains($user); // FALSE
|
||||
|
||||
@@ -422,7 +422,7 @@ comment might look like in your controller (without ``cascade: persist``):
|
||||
$user = new User();
|
||||
$myFirstComment = new Comment();
|
||||
$user->addComment($myFirstComment);
|
||||
|
||||
|
||||
$em->persist($user);
|
||||
$em->persist($myFirstComment); // required, if `cascade: persist` is not set
|
||||
$em->flush();
|
||||
@@ -480,7 +480,7 @@ If you then set up the cascading to the ``User#commentsAuthored`` property...
|
||||
<?php
|
||||
$user = new User();
|
||||
$user->comment('Lorem ipsum', new DateTime());
|
||||
|
||||
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
|
||||
@@ -559,6 +559,13 @@ OrphanRemoval works with one-to-one, one-to-many and many-to-many associations.
|
||||
If you neglect this assumption your entities will get deleted by Doctrine even if
|
||||
you assigned the orphaned entity to another one.
|
||||
|
||||
.. note::
|
||||
|
||||
``orphanRemoval=true`` option should be used in combination with ``cascade=["persist"]`` option
|
||||
as the child entity, that is manually persisted, will not be deleted automatically by Doctrine
|
||||
when a collection is still an instance of ArrayCollection (before first flush / hydration).
|
||||
This is a Doctrine limitation since ArrayCollection does not have access to a UnitOfWork.
|
||||
|
||||
As a better example consider an Addressbook application where you have Contacts, Addresses
|
||||
and StandingData:
|
||||
|
||||
@@ -578,10 +585,10 @@ and StandingData:
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
private $id;
|
||||
|
||||
/** @OneToOne(targetEntity="StandingData", orphanRemoval=true) */
|
||||
/** @OneToOne(targetEntity="StandingData", cascade={"persist"}, orphanRemoval=true) */
|
||||
private $standingData;
|
||||
|
||||
/** @OneToMany(targetEntity="Address", mappedBy="contact", orphanRemoval=true) */
|
||||
/** @OneToMany(targetEntity="Address", mappedBy="contact", cascade={"persist"}, orphanRemoval=true) */
|
||||
private $addresses;
|
||||
|
||||
public function __construct()
|
||||
@@ -612,10 +619,10 @@ Now two examples of what happens when you remove the references:
|
||||
|
||||
$em->flush();
|
||||
|
||||
In this case you have not only changed the ``Contact`` entity itself but
|
||||
you have also removed the references for standing data and as well as one
|
||||
address reference. When flush is called not only are the references removed
|
||||
but both the old standing data and the one address entity are also deleted
|
||||
In this case you have not only changed the ``Contact`` entity itself but
|
||||
you have also removed the references for standing data and as well as one
|
||||
address reference. When flush is called not only are the references removed
|
||||
but both the old standing data and the one address entity are also deleted
|
||||
from the database.
|
||||
|
||||
.. _filtering-collections:
|
||||
|
||||
@@ -32,10 +32,13 @@ use function array_map;
|
||||
use function array_shift;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function func_num_args;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_numeric;
|
||||
use function is_object;
|
||||
use function is_scalar;
|
||||
use function is_string;
|
||||
use function iterator_count;
|
||||
use function iterator_to_array;
|
||||
use function ksort;
|
||||
@@ -195,9 +198,7 @@ abstract class AbstractQuery
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool TRUE if the query results are enable for second level cache, FALSE otherwise.
|
||||
*/
|
||||
/** @return bool TRUE if the query results are enabled for second level cache, FALSE otherwise. */
|
||||
public function isCacheable()
|
||||
{
|
||||
return $this->cacheable;
|
||||
@@ -225,17 +226,13 @@ abstract class AbstractQuery
|
||||
return $this->cacheRegion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool TRUE if the query cache and second level cache are enabled, FALSE otherwise.
|
||||
*/
|
||||
/** @return bool TRUE if the query cache and second level cache are enabled, FALSE otherwise. */
|
||||
protected function isCacheEnabled()
|
||||
{
|
||||
return $this->cacheable && $this->hasCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
/** @return int */
|
||||
public function getLifetime()
|
||||
{
|
||||
return $this->lifetime;
|
||||
@@ -282,7 +279,7 @@ abstract class AbstractQuery
|
||||
* The returned SQL syntax depends on the connection driver that is used
|
||||
* by this query object at the time of this method call.
|
||||
*
|
||||
* @return string SQL query
|
||||
* @return list<string>|string SQL query
|
||||
*/
|
||||
abstract public function getSQL();
|
||||
|
||||
@@ -324,7 +321,7 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Gets a query parameter.
|
||||
*
|
||||
* @param mixed $key The key (index or name) of the bound parameter.
|
||||
* @param int|string $key The key (index or name) of the bound parameter.
|
||||
*
|
||||
* @return Parameter|null The value of the bound parameter, or NULL if not available.
|
||||
*/
|
||||
@@ -353,7 +350,6 @@ abstract class AbstractQuery
|
||||
*/
|
||||
public function setParameters($parameters)
|
||||
{
|
||||
// BC compatibility with 2.3-
|
||||
if (is_array($parameters)) {
|
||||
/** @psalm-var ArrayCollection<int, Parameter> $parameterCollection */
|
||||
$parameterCollection = new ArrayCollection();
|
||||
@@ -401,8 +397,7 @@ abstract class AbstractQuery
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed[]|string|int|float|bool
|
||||
* @psalm-return array|scalar
|
||||
* @return mixed
|
||||
*
|
||||
* @throws ORMInvalidArgumentException
|
||||
*/
|
||||
@@ -547,6 +542,15 @@ abstract class AbstractQuery
|
||||
public function setHydrationCacheProfile(?QueryCacheProfile $profile = null)
|
||||
{
|
||||
if ($profile === null) {
|
||||
if (func_num_args() < 1) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/9791',
|
||||
'Calling %s without arguments is deprecated, pass null instead.',
|
||||
__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->_hydrationCacheProfile = null;
|
||||
|
||||
return $this;
|
||||
@@ -572,9 +576,7 @@ abstract class AbstractQuery
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return QueryCacheProfile|null
|
||||
*/
|
||||
/** @return QueryCacheProfile|null */
|
||||
public function getHydrationCacheProfile()
|
||||
{
|
||||
return $this->_hydrationCacheProfile;
|
||||
@@ -591,6 +593,15 @@ abstract class AbstractQuery
|
||||
public function setResultCacheProfile(?QueryCacheProfile $profile = null)
|
||||
{
|
||||
if ($profile === null) {
|
||||
if (func_num_args() < 1) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/9791',
|
||||
'Calling %s without arguments is deprecated, pass null instead.',
|
||||
__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->_queryCacheProfile = null;
|
||||
|
||||
return $this;
|
||||
@@ -645,6 +656,15 @@ abstract class AbstractQuery
|
||||
public function setResultCache(?CacheItemPoolInterface $resultCache = null)
|
||||
{
|
||||
if ($resultCache === null) {
|
||||
if (func_num_args() < 1) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/9791',
|
||||
'Calling %s without arguments is deprecated, pass null instead.',
|
||||
__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->_queryCacheProfile) {
|
||||
$this->_queryCacheProfile = new QueryCacheProfile($this->_queryCacheProfile->getLifetime(), $this->_queryCacheProfile->getCacheKey());
|
||||
}
|
||||
@@ -806,9 +826,7 @@ abstract class AbstractQuery
|
||||
return $this->_expireResultCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return QueryCacheProfile|null
|
||||
*/
|
||||
/** @return QueryCacheProfile|null */
|
||||
public function getQueryCacheProfile()
|
||||
{
|
||||
return $this->_queryCacheProfile;
|
||||
@@ -817,17 +835,22 @@ abstract class AbstractQuery
|
||||
/**
|
||||
* Change the default fetch mode of an association for this query.
|
||||
*
|
||||
* $fetchMode can be one of ClassMetadata::FETCH_EAGER or ClassMetadata::FETCH_LAZY
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $assocName
|
||||
* @param int $fetchMode
|
||||
* @param class-string $class
|
||||
* @param string $assocName
|
||||
* @param int $fetchMode
|
||||
* @psalm-param Mapping\ClassMetadata::FETCH_EAGER|Mapping\ClassMetadata::FETCH_LAZY $fetchMode
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setFetchMode($class, $assocName, $fetchMode)
|
||||
{
|
||||
if ($fetchMode !== Mapping\ClassMetadata::FETCH_EAGER) {
|
||||
if (! in_array($fetchMode, [Mapping\ClassMetadata::FETCH_EAGER, Mapping\ClassMetadata::FETCH_LAZY], true)) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/9777',
|
||||
'Calling %s() with something else than ClassMetadata::FETCH_EAGER or ClassMetadata::FETCH_LAZY is deprecated.',
|
||||
__METHOD__
|
||||
);
|
||||
$fetchMode = Mapping\ClassMetadata::FETCH_LAZY;
|
||||
}
|
||||
|
||||
@@ -1302,7 +1325,8 @@ abstract class AbstractQuery
|
||||
$parameters[$parameter->getName()] = $this->processParameterValue($parameter->getValue());
|
||||
}
|
||||
|
||||
$sql = $this->getSQL();
|
||||
$sql = $this->getSQL();
|
||||
assert(is_string($sql));
|
||||
$queryCacheProfile = $this->getHydrationCacheProfile();
|
||||
$hints = $this->getHints();
|
||||
$hints['hydrationMode'] = $this->getHydrationMode();
|
||||
@@ -1374,7 +1398,8 @@ abstract class AbstractQuery
|
||||
*/
|
||||
protected function getHash()
|
||||
{
|
||||
$query = $this->getSQL();
|
||||
$query = $this->getSQL();
|
||||
assert(is_string($query));
|
||||
$hints = $this->getHints();
|
||||
$params = array_map(function (Parameter $parameter) {
|
||||
$value = $parameter->getValue();
|
||||
|
||||
@@ -23,41 +23,31 @@ class CacheConfiguration
|
||||
/** @var QueryCacheValidator|null */
|
||||
private $queryValidator;
|
||||
|
||||
/**
|
||||
* @return CacheFactory|null
|
||||
*/
|
||||
/** @return CacheFactory|null */
|
||||
public function getCacheFactory()
|
||||
{
|
||||
return $this->cacheFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
/** @return void */
|
||||
public function setCacheFactory(CacheFactory $factory)
|
||||
{
|
||||
$this->cacheFactory = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CacheLogger|null
|
||||
*/
|
||||
/** @return CacheLogger|null */
|
||||
public function getCacheLogger()
|
||||
{
|
||||
return $this->cacheLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
/** @return void */
|
||||
public function setCacheLogger(CacheLogger $logger)
|
||||
{
|
||||
$this->cacheLogger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RegionsConfiguration
|
||||
*/
|
||||
/** @return RegionsConfiguration */
|
||||
public function getRegionsConfiguration()
|
||||
{
|
||||
if ($this->regionsConfig === null) {
|
||||
@@ -67,17 +57,13 @@ class CacheConfiguration
|
||||
return $this->regionsConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
/** @return void */
|
||||
public function setRegionsConfiguration(RegionsConfiguration $regionsConfig)
|
||||
{
|
||||
$this->regionsConfig = $regionsConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return QueryCacheValidator
|
||||
*/
|
||||
/** @return QueryCacheValidator */
|
||||
public function getQueryValidator()
|
||||
{
|
||||
if ($this->queryValidator === null) {
|
||||
@@ -89,9 +75,7 @@ class CacheConfiguration
|
||||
return $this->queryValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
/** @return void */
|
||||
public function setQueryValidator(QueryCacheValidator $validator)
|
||||
{
|
||||
$this->queryValidator = $validator;
|
||||
|
||||
@@ -17,9 +17,7 @@ class CollectionCacheEntry implements CacheEntry
|
||||
*/
|
||||
public $identifiers;
|
||||
|
||||
/**
|
||||
* @param CacheKey[] $identifiers List of entity identifiers hold by the collection
|
||||
*/
|
||||
/** @param CacheKey[] $identifiers List of entity identifiers hold by the collection */
|
||||
public function __construct(array $identifiers)
|
||||
{
|
||||
$this->identifiers = $identifiers;
|
||||
|
||||
@@ -20,8 +20,6 @@ interface CollectionHydrator
|
||||
*/
|
||||
public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, $collection);
|
||||
|
||||
/**
|
||||
* @return mixed[]|null
|
||||
*/
|
||||
/** @return mixed[]|null */
|
||||
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection);
|
||||
}
|
||||
|
||||
@@ -262,9 +262,7 @@ class DefaultCache implements Cache
|
||||
return $this->queryCaches[$regionName];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*/
|
||||
/** @param mixed $identifier The entity identifier. */
|
||||
private function buildEntityCacheKey(ClassMetadata $metadata, $identifier): EntityCacheKey
|
||||
{
|
||||
if (! is_array($identifier)) {
|
||||
@@ -274,9 +272,7 @@ class DefaultCache implements Cache
|
||||
return new EntityCacheKey($metadata->rootEntityName, $identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $ownerIdentifier The identifier of the owning entity.
|
||||
*/
|
||||
/** @param mixed $ownerIdentifier The identifier of the owning entity. */
|
||||
private function buildCollectionCacheKey(
|
||||
ClassMetadata $metadata,
|
||||
string $association,
|
||||
|
||||
@@ -49,9 +49,7 @@ class DefaultCacheFactory implements CacheFactory
|
||||
/** @var string|null */
|
||||
private $fileLockRegionDirectory;
|
||||
|
||||
/**
|
||||
* @param CacheItemPoolInterface $cacheItemPool
|
||||
*/
|
||||
/** @param CacheItemPoolInterface $cacheItemPool */
|
||||
public function __construct(RegionsConfiguration $cacheConfig, $cacheItemPool)
|
||||
{
|
||||
if ($cacheItemPool instanceof LegacyCache) {
|
||||
@@ -89,25 +87,19 @@ class DefaultCacheFactory implements CacheFactory
|
||||
$this->fileLockRegionDirectory = (string) $fileLockRegionDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
/** @return string */
|
||||
public function getFileLockRegionDirectory()
|
||||
{
|
||||
return $this->fileLockRegionDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
/** @return void */
|
||||
public function setRegion(Region $region)
|
||||
{
|
||||
$this->regions[$region->getName()] = $region;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
/** @return void */
|
||||
public function setTimestampRegion(TimestampRegion $region)
|
||||
{
|
||||
$this->timestampRegion = $region;
|
||||
|
||||
@@ -27,9 +27,7 @@ class DefaultCollectionHydrator implements CollectionHydrator
|
||||
/** @var array<string,mixed> */
|
||||
private static $hints = [Query::HINT_CACHE_ENABLED => true];
|
||||
|
||||
/**
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
*/
|
||||
/** @param EntityManagerInterface $em The entity manager. */
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
|
||||
@@ -12,6 +12,7 @@ use Doctrine\ORM\UnitOfWork;
|
||||
use Doctrine\ORM\Utility\IdentifierFlattener;
|
||||
|
||||
use function array_merge;
|
||||
use function assert;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function reset;
|
||||
@@ -37,9 +38,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
/** @var array<string,mixed> */
|
||||
private static $hints = [Query::HINT_CACHE_ENABLED => true];
|
||||
|
||||
/**
|
||||
* @param EntityManagerInterface $em The entity manager.
|
||||
*/
|
||||
/** @param EntityManagerInterface $em The entity manager. */
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
@@ -57,6 +56,7 @@ class DefaultEntityHydrator implements EntityHydrator
|
||||
|
||||
if ($metadata->requiresFetchAfterChange) {
|
||||
if ($metadata->isVersioned) {
|
||||
assert($metadata->versionField !== null);
|
||||
$data[$metadata->versionField] = $metadata->getFieldValue($entity, $metadata->versionField);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Cache\Exception;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
/** @deprecated */
|
||||
final class InvalidResultCacheDriver extends CacheException
|
||||
{
|
||||
public static function create(): self
|
||||
|
||||
@@ -21,9 +21,7 @@ class Lock
|
||||
$this->time = $time ?: time();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Lock
|
||||
*/
|
||||
/** @return Lock */
|
||||
public static function createLockRead()
|
||||
{
|
||||
return new self(uniqid((string) time(), true));
|
||||
|
||||
@@ -33,9 +33,7 @@ class CacheLoggerChain implements CacheLogger
|
||||
return $this->loggers[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, CacheLogger>
|
||||
*/
|
||||
/** @return array<string, CacheLogger> */
|
||||
public function getLoggers()
|
||||
{
|
||||
return $this->loggers;
|
||||
|
||||
@@ -141,25 +141,19 @@ class StatisticsCacheLogger implements CacheLogger
|
||||
return $this->cachePutCountMap[$regionName] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, int>
|
||||
*/
|
||||
/** @return array<string, int> */
|
||||
public function getRegionsMiss()
|
||||
{
|
||||
return $this->cacheMissCountMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, int>
|
||||
*/
|
||||
/** @return array<string, int> */
|
||||
public function getRegionsHit()
|
||||
{
|
||||
return $this->cacheHitCountMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, int>
|
||||
*/
|
||||
/** @return array<string, int> */
|
||||
public function getRegionsPut()
|
||||
{
|
||||
return $this->cachePutCountMap;
|
||||
|
||||
@@ -16,14 +16,10 @@ use Doctrine\ORM\Persisters\Collection\CollectionPersister;
|
||||
*/
|
||||
interface CachedCollectionPersister extends CachedPersister, CollectionPersister
|
||||
{
|
||||
/**
|
||||
* @return ClassMetadata
|
||||
*/
|
||||
/** @return ClassMetadata */
|
||||
public function getSourceEntityMetadata();
|
||||
|
||||
/**
|
||||
* @return ClassMetadata
|
||||
*/
|
||||
/** @return ClassMetadata */
|
||||
public function getTargetEntityMetadata();
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,9 +14,7 @@ use function spl_object_id;
|
||||
|
||||
class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
|
||||
{
|
||||
/**
|
||||
* @param mixed[] $association The association mapping.
|
||||
*/
|
||||
/** @param mixed[] $association The association mapping. */
|
||||
public function __construct(CollectionPersister $persister, ConcurrentRegion $region, EntityManagerInterface $em, array $association)
|
||||
{
|
||||
parent::__construct($persister, $region, $em, $association);
|
||||
|
||||
@@ -177,9 +177,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
return $this->region;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityHydrator
|
||||
*/
|
||||
/** @return EntityHydrator */
|
||||
public function getEntityHydrator()
|
||||
{
|
||||
return $this->hydrator;
|
||||
@@ -207,9 +205,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
return $cached;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $entity
|
||||
*/
|
||||
/** @param object $entity */
|
||||
private function storeJoinedAssociations($entity): void
|
||||
{
|
||||
if ($this->joinedAssociations === null) {
|
||||
|
||||
@@ -14,9 +14,7 @@ use Doctrine\ORM\Persisters\Entity\EntityPersister;
|
||||
*/
|
||||
interface CachedEntityPersister extends CachedPersister, EntityPersister
|
||||
{
|
||||
/**
|
||||
* @return EntityHydrator
|
||||
*/
|
||||
/** @return EntityHydrator */
|
||||
public function getEntityHydrator();
|
||||
|
||||
/**
|
||||
|
||||
@@ -82,9 +82,7 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
|
||||
$this->queuedCache['update'][] = $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $entity
|
||||
*/
|
||||
/** @param object $entity */
|
||||
private function updateCache($entity, bool $isChanged): bool
|
||||
{
|
||||
$class = $this->metadataFactory->getMetadataFor(get_class($entity));
|
||||
|
||||
@@ -12,9 +12,7 @@ use Doctrine\ORM\Query\ResultSetMapping;
|
||||
*/
|
||||
interface QueryCache
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
/** @return bool */
|
||||
public function clear();
|
||||
|
||||
/**
|
||||
@@ -32,8 +30,6 @@ interface QueryCache
|
||||
*/
|
||||
public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = []);
|
||||
|
||||
/**
|
||||
* @return Region
|
||||
*/
|
||||
/** @return Region */
|
||||
public function getRegion();
|
||||
}
|
||||
|
||||
@@ -34,9 +34,7 @@ class QueryCacheKey extends CacheKey
|
||||
*/
|
||||
public $timestampKey;
|
||||
|
||||
/**
|
||||
* @psalm-param Cache::MODE_* $cacheMode
|
||||
*/
|
||||
/** @psalm-param Cache::MODE_* $cacheMode */
|
||||
public function __construct(
|
||||
string $cacheId,
|
||||
int $lifetime = 0,
|
||||
|
||||
@@ -31,9 +31,7 @@ use function strtr;
|
||||
*/
|
||||
class DefaultRegion implements Region
|
||||
{
|
||||
/**
|
||||
* @internal since 2.11, this constant will be private in 3.0.
|
||||
*/
|
||||
/** @internal since 2.11, this constant will be private in 3.0. */
|
||||
public const REGION_KEY_SEPARATOR = '_';
|
||||
private const REGION_PREFIX = 'DC2_REGION_';
|
||||
|
||||
@@ -61,9 +59,7 @@ class DefaultRegion implements Region
|
||||
/** @var CacheItemPoolInterface */
|
||||
private $cacheItemPool;
|
||||
|
||||
/**
|
||||
* @param CacheItemPoolInterface $cacheItemPool
|
||||
*/
|
||||
/** @param CacheItemPoolInterface $cacheItemPool */
|
||||
public function __construct(string $name, $cacheItemPool, int $lifetime = 0)
|
||||
{
|
||||
if ($cacheItemPool instanceof LegacyCache) {
|
||||
|
||||
@@ -103,17 +103,13 @@ class FileLockRegion implements ConcurrentRegion
|
||||
return $this->directory . DIRECTORY_SEPARATOR . $key->hash . '.' . self::LOCK_EXTENSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|false
|
||||
*/
|
||||
/** @return string|false */
|
||||
private function getLockContent(string $filename)
|
||||
{
|
||||
return @file_get_contents($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|false
|
||||
*/
|
||||
/** @return int|false */
|
||||
private function getLockTime(string $filename)
|
||||
{
|
||||
return @fileatime($filename);
|
||||
|
||||
@@ -31,9 +31,7 @@ class RegionsConfiguration
|
||||
$this->defaultLockLifetime = (int) $defaultLockLifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
/** @return int */
|
||||
public function getDefaultLifetime()
|
||||
{
|
||||
return $this->defaultLifetime;
|
||||
@@ -49,9 +47,7 @@ class RegionsConfiguration
|
||||
$this->defaultLifetime = (int) $defaultLifetime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
/** @return int */
|
||||
public function getDefaultLockLifetime()
|
||||
{
|
||||
return $this->defaultLockLifetime;
|
||||
|
||||
@@ -17,9 +17,7 @@ class TimestampCacheEntry implements CacheEntry
|
||||
*/
|
||||
public $time;
|
||||
|
||||
/**
|
||||
* @param float|null $time
|
||||
*/
|
||||
/** @param float|null $time */
|
||||
public function __construct($time = null)
|
||||
{
|
||||
$this->time = $time ? (float) $time : microtime(true);
|
||||
|
||||
@@ -9,9 +9,7 @@ namespace Doctrine\ORM\Cache;
|
||||
*/
|
||||
class TimestampCacheKey extends CacheKey
|
||||
{
|
||||
/**
|
||||
* @param string $space Result cache id
|
||||
*/
|
||||
/** @param string $space Result cache id */
|
||||
public function __construct($space)
|
||||
{
|
||||
$this->hash = (string) $space;
|
||||
|
||||
@@ -37,6 +37,7 @@ use Doctrine\ORM\Mapping\EntityListenerResolver;
|
||||
use Doctrine\ORM\Mapping\NamingStrategy;
|
||||
use Doctrine\ORM\Mapping\QuoteStrategy;
|
||||
use Doctrine\ORM\Proxy\ProxyFactory;
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\Filter\SQLFilter;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
|
||||
@@ -103,6 +104,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\Common\Proxy\AbstractProxyFactory.
|
||||
* @psalm-param bool|AutogenerateMode $autoGenerate
|
||||
* True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
|
||||
*
|
||||
* @return void
|
||||
@@ -592,8 +594,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param string $name Function name.
|
||||
* @param string|callable $className Class name or a callable that returns the function.
|
||||
* @param string $name Function name.
|
||||
* @param class-string|callable $className Class name or a callable that returns the function.
|
||||
* @psalm-param class-string<FunctionNode>|callable(string):FunctionNode $className
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -607,8 +610,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|null
|
||||
* @psalm-return ?class-string
|
||||
* @return string|callable|null
|
||||
* @psalm-return class-string<FunctionNode>|callable(string):FunctionNode|null
|
||||
*/
|
||||
public function getCustomStringFunction($name)
|
||||
{
|
||||
@@ -625,7 +628,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* Any previously added string functions are discarded.
|
||||
*
|
||||
* @psalm-param array<string, class-string> $functions The map of custom
|
||||
* @psalm-param array<string, class-string<FunctionNode>|callable(string):FunctionNode> $functions The map of custom
|
||||
* DQL string functions.
|
||||
*
|
||||
* @return void
|
||||
@@ -644,8 +647,9 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* DQL function names are case-insensitive.
|
||||
*
|
||||
* @param string $name Function name.
|
||||
* @param string|callable $className Class name or a callable that returns the function.
|
||||
* @param string $name Function name.
|
||||
* @param class-string|callable $className Class name or a callable that returns the function.
|
||||
* @psalm-param class-string<FunctionNode>|callable(string):FunctionNode $className
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -659,8 +663,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|null
|
||||
* @psalm-return ?class-string
|
||||
* @return string|callable|null
|
||||
* @psalm-return class-string|callable|null
|
||||
*/
|
||||
public function getCustomNumericFunction($name)
|
||||
{
|
||||
@@ -698,7 +702,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $name Function name.
|
||||
* @param string|callable $className Class name or a callable that returns the function.
|
||||
* @psalm-param class-string|callable $className
|
||||
* @psalm-param class-string<FunctionNode>|callable(string):FunctionNode $className
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -712,8 +716,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|null
|
||||
* @psalm-return ?class-string $name
|
||||
* @return string|callable|null
|
||||
* @psalm-return class-string|callable|null $name
|
||||
*/
|
||||
public function getCustomDatetimeFunction($name)
|
||||
{
|
||||
@@ -731,7 +735,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
* Any previously added date/time functions are discarded.
|
||||
*
|
||||
* @param array $functions The map of custom DQL date/time functions.
|
||||
* @psalm-param array<string, string> $functions
|
||||
* @psalm-param array<string, class-string<FunctionNode>|callable(string):FunctionNode> $functions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -971,9 +975,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
return $this->_attributes['repositoryFactory'] ?? new DefaultRepositoryFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
/** @return bool */
|
||||
public function isSecondLevelCacheEnabled()
|
||||
{
|
||||
return $this->_attributes['isSecondLevelCacheEnabled'] ?? false;
|
||||
@@ -989,17 +991,13 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
$this->_attributes['isSecondLevelCacheEnabled'] = (bool) $flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
/** @return void */
|
||||
public function setSecondLevelCacheConfiguration(CacheConfiguration $cacheConfig)
|
||||
{
|
||||
$this->_attributes['secondLevelCacheConfiguration'] = $cacheConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CacheConfiguration|null
|
||||
*/
|
||||
/** @return CacheConfiguration|null */
|
||||
public function getSecondLevelCacheConfiguration()
|
||||
{
|
||||
if (! isset($this->_attributes['secondLevelCacheConfiguration']) && $this->isSecondLevelCacheEnabled()) {
|
||||
|
||||
@@ -35,7 +35,6 @@ use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
use function array_keys;
|
||||
use function call_user_func;
|
||||
use function class_exists;
|
||||
use function get_debug_type;
|
||||
use function gettype;
|
||||
@@ -71,8 +70,10 @@ use function strpos;
|
||||
* is not a valid extension point for the EntityManager. Instead you
|
||||
* should take a look at the {@see \Doctrine\ORM\Decorator\EntityManagerDecorator}
|
||||
* and wrap your entity manager in a decorator.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
/* final */class EntityManager implements EntityManagerInterface
|
||||
class EntityManager implements EntityManagerInterface
|
||||
{
|
||||
/**
|
||||
* The used Configuration.
|
||||
@@ -155,11 +156,15 @@ use function strpos;
|
||||
* Creates a new EntityManager that operates on the given database connection
|
||||
* and uses the given Configuration and EventManager implementations.
|
||||
*/
|
||||
protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
|
||||
public function __construct(Connection $conn, Configuration $config)
|
||||
{
|
||||
if (! $config->getMetadataDriverImpl()) {
|
||||
throw MissingMappingDriverImplementation::create();
|
||||
}
|
||||
|
||||
$this->conn = $conn;
|
||||
$this->config = $config;
|
||||
$this->eventManager = $eventManager;
|
||||
$this->eventManager = $conn->getEventManager();
|
||||
|
||||
$metadataFactoryClassName = $config->getClassMetadataFactoryName();
|
||||
|
||||
@@ -242,7 +247,7 @@ use function strpos;
|
||||
$this->conn->beginTransaction();
|
||||
|
||||
try {
|
||||
$return = call_user_func($func, $this);
|
||||
$return = $func($this);
|
||||
|
||||
$this->flush();
|
||||
$this->conn->commit();
|
||||
@@ -959,13 +964,9 @@ use function strpos;
|
||||
*/
|
||||
public static function create($connection, Configuration $config, ?EventManager $eventManager = null)
|
||||
{
|
||||
if (! $config->getMetadataDriverImpl()) {
|
||||
throw MissingMappingDriverImplementation::create();
|
||||
}
|
||||
|
||||
$connection = static::createConnection($connection, $config, $eventManager);
|
||||
|
||||
return new EntityManager($connection, $config, $connection->getEventManager());
|
||||
return new EntityManager($connection, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -65,9 +65,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
/** @var Inflector|null */
|
||||
private static $inflector;
|
||||
|
||||
/**
|
||||
* @psalm-param ClassMetadata<T> $class
|
||||
*/
|
||||
/** @psalm-param ClassMetadata<T> $class */
|
||||
public function __construct(EntityManagerInterface $em, ClassMetadata $class)
|
||||
{
|
||||
$this->_entityName = $class->name;
|
||||
@@ -306,9 +304,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
return $this->getEntityName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EntityManagerInterface
|
||||
*/
|
||||
/** @return EntityManagerInterface */
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->_em;
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
|
||||
|
||||
@@ -15,23 +16,55 @@ use Doctrine\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
|
||||
*/
|
||||
class LifecycleEventArgs extends BaseLifecycleEventArgs
|
||||
{
|
||||
/** @param object $object */
|
||||
public function __construct($object, EntityManagerInterface $objectManager)
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/9875',
|
||||
'The %s class is deprecated and will be removed in ORM 3.0. Use %s instead.',
|
||||
self::class,
|
||||
BaseLifecycleEventArgs::class
|
||||
);
|
||||
|
||||
parent::__construct($object, $objectManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves associated Entity.
|
||||
*
|
||||
* @deprecated 2.13. Use {@see getObject} instead.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function getEntity()
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/9875',
|
||||
'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use getObjectManager() instead.',
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
return $this->getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves associated EntityManager.
|
||||
*
|
||||
* @deprecated 2.13. Use {@see getObjectManager} instead.
|
||||
*
|
||||
* @return EntityManagerInterface
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/9875',
|
||||
'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use getObjectManager() instead.',
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
return $this->getObjectManager();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,6 @@ class ListenersInvoker
|
||||
*/
|
||||
private $eventManager;
|
||||
|
||||
/**
|
||||
* Initializes a new ListenersInvoker instance.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->eventManager = $em->getEventManager();
|
||||
@@ -46,6 +43,7 @@ class ListenersInvoker
|
||||
* @param string $eventName The entity lifecycle event.
|
||||
*
|
||||
* @return int Bitmask of subscribed event systems.
|
||||
* @psalm-return int-mask-of<self::INVOKE_*>
|
||||
*/
|
||||
public function getSubscribedSystems(ClassMetadata $metadata, $eventName)
|
||||
{
|
||||
@@ -74,6 +72,7 @@ class ListenersInvoker
|
||||
* @param object $entity The Entity on which the event occurred.
|
||||
* @param EventArgs $event The Event args.
|
||||
* @param int $invoke Bitmask to invoke listeners.
|
||||
* @psalm-param int-mask-of<self::INVOKE_*> $invoke
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -4,11 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\Persistence\Event\ManagerEventArgs;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
|
||||
use function func_num_args;
|
||||
|
||||
/**
|
||||
* Class that holds event arguments for a `onClassMetadataNotFound` event.
|
||||
*
|
||||
@@ -36,17 +39,22 @@ class OnClassMetadataNotFoundEventArgs extends ManagerEventArgs
|
||||
parent::__construct($objectManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
/** @return void */
|
||||
public function setFoundMetadata(?ClassMetadata $classMetadata = null)
|
||||
{
|
||||
if (func_num_args() < 1) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/9791',
|
||||
'Calling %s without arguments is deprecated, pass null instead.',
|
||||
__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->foundMetadata = $classMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadata|null
|
||||
*/
|
||||
/** @return ClassMetadata|null */
|
||||
public function getFoundMetadata()
|
||||
{
|
||||
return $this->foundMetadata;
|
||||
|
||||
@@ -4,39 +4,47 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\Persistence\Event\OnClearEventArgs as BaseOnClearEventArgs;
|
||||
|
||||
/**
|
||||
* Provides event arguments for the onClear event.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @extends BaseOnClearEventArgs<EntityManagerInterface>
|
||||
*/
|
||||
class OnClearEventArgs extends EventArgs
|
||||
class OnClearEventArgs extends BaseOnClearEventArgs
|
||||
{
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
/** @var string|null */
|
||||
private $entityClass;
|
||||
|
||||
/**
|
||||
* @param string|null $entityClass Optional entity class.
|
||||
*/
|
||||
/** @param string|null $entityClass Optional entity class. */
|
||||
public function __construct(EntityManagerInterface $em, $entityClass = null)
|
||||
{
|
||||
$this->em = $em;
|
||||
parent::__construct($em);
|
||||
|
||||
$this->entityClass = $entityClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves associated EntityManager.
|
||||
*
|
||||
* @deprecated 2.13. Use {@see getObjectManager} instead.
|
||||
*
|
||||
* @return EntityManagerInterface
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
return $this->em;
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/9875',
|
||||
'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use getObjectManager() instead.',
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
return $this->getObjectManager();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,31 +4,35 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\Persistence\Event\ManagerEventArgs;
|
||||
|
||||
/**
|
||||
* Provides event arguments for the preFlush event.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @extends ManagerEventArgs<EntityManagerInterface>
|
||||
*/
|
||||
class OnFlushEventArgs extends EventArgs
|
||||
class OnFlushEventArgs extends ManagerEventArgs
|
||||
{
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve associated EntityManager.
|
||||
*
|
||||
* @deprecated 2.13. Use {@see getObjectManager} instead.
|
||||
*
|
||||
* @return EntityManagerInterface
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
return $this->em;
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/9875',
|
||||
'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use getObjectManager() instead.',
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
return $this->getObjectManager();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,31 +4,35 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\Persistence\Event\ManagerEventArgs;
|
||||
|
||||
/**
|
||||
* Provides event arguments for the postFlush event.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @extends ManagerEventArgs<EntityManagerInterface>
|
||||
*/
|
||||
class PostFlushEventArgs extends EventArgs
|
||||
class PostFlushEventArgs extends ManagerEventArgs
|
||||
{
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves associated EntityManager.
|
||||
*
|
||||
* @deprecated 2.13. Use {@see getObjectManager} instead.
|
||||
*
|
||||
* @return EntityManagerInterface
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
return $this->em;
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/9875',
|
||||
'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use getObjectManager() instead.',
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
return $this->getObjectManager();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,29 +4,33 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\Persistence\Event\ManagerEventArgs;
|
||||
|
||||
/**
|
||||
* Provides event arguments for the preFlush event.
|
||||
*
|
||||
* @link www.doctrine-project.com
|
||||
*
|
||||
* @extends ManagerEventArgs<EntityManagerInterface>
|
||||
*/
|
||||
class PreFlushEventArgs extends EventArgs
|
||||
class PreFlushEventArgs extends ManagerEventArgs
|
||||
{
|
||||
/** @var EntityManagerInterface */
|
||||
private $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 2.13. Use {@see getObjectManager} instead.
|
||||
*
|
||||
* @return EntityManagerInterface
|
||||
*/
|
||||
public function getEntityManager()
|
||||
{
|
||||
return $this->em;
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/9875',
|
||||
'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use getObjectManager() instead.',
|
||||
__METHOD__
|
||||
);
|
||||
|
||||
return $this->getObjectManager();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Field "%s" is not a valid field of the entity "%s" in PreUpdateEventArgs.',
|
||||
$field,
|
||||
get_debug_type($this->getEntity())
|
||||
get_debug_type($this->getObject())
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,7 @@ use function get_debug_type;
|
||||
|
||||
final class EntityMissingAssignedId extends ORMException
|
||||
{
|
||||
/**
|
||||
* @param object $entity
|
||||
*/
|
||||
/** @param object $entity */
|
||||
public static function forField($entity, string $field): self
|
||||
{
|
||||
return new self('Entity of type ' . get_debug_type($entity) . " is missing an assigned ID for field '" . $field . "'. " .
|
||||
|
||||
@@ -11,9 +11,7 @@ final class MultipleSelectorsFoundException extends ORMException
|
||||
{
|
||||
public const MULTIPLE_SELECTORS_FOUND_EXCEPTION = 'Multiple selectors found: %s. Please select only one.';
|
||||
|
||||
/**
|
||||
* @param string[] $selectors
|
||||
*/
|
||||
/** @param string[] $selectors */
|
||||
public static function create(array $selectors): self
|
||||
{
|
||||
return new self(
|
||||
|
||||
@@ -6,9 +6,7 @@ namespace Doctrine\ORM\Exception;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @deprecated No replacement planned.
|
||||
*/
|
||||
/** @deprecated No replacement planned. */
|
||||
final class UnknownEntityNamespace extends ORMException implements ConfigurationException
|
||||
{
|
||||
public static function fromNamespaceAlias(string $entityNamespaceAlias): self
|
||||
|
||||
@@ -9,9 +9,7 @@ use function sprintf;
|
||||
|
||||
final class UnrecognizedIdentifierFields extends ORMException implements ManagerException
|
||||
{
|
||||
/**
|
||||
* @param string[] $fieldNames
|
||||
*/
|
||||
/** @param string[] $fieldNames */
|
||||
public static function fromClassAndFieldNames(string $className, array $fieldNames): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
@@ -27,6 +28,15 @@ class BigIntegerIdentityGenerator extends AbstractIdGenerator
|
||||
*/
|
||||
public function __construct($sequenceName = null)
|
||||
{
|
||||
if ($sequenceName !== null) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/8850',
|
||||
'Passing a sequence name to the IdentityGenerator is deprecated in favor of using %s. $sequenceName will be removed in ORM 3.0',
|
||||
SequenceGenerator::class
|
||||
);
|
||||
}
|
||||
|
||||
$this->sequenceName = $sequenceName;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Id;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
@@ -27,6 +28,15 @@ class IdentityGenerator extends AbstractIdGenerator
|
||||
*/
|
||||
public function __construct($sequenceName = null)
|
||||
{
|
||||
if ($sequenceName !== null) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/8850',
|
||||
'Passing a sequence name to the IdentityGenerator is deprecated in favor of using %s. $sequenceName will be removed in ORM 3.0',
|
||||
SequenceGenerator::class
|
||||
);
|
||||
}
|
||||
|
||||
$this->sequenceName = $sequenceName;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
$connection->ensureConnectedToPrimary();
|
||||
}
|
||||
|
||||
$this->_nextValue = (int) $connection->executeQuery($sql)->fetchOne();
|
||||
$this->_nextValue = (int) $connection->fetchOne($sql);
|
||||
$this->_maxValue = $this->_nextValue + $this->_allocationSize;
|
||||
}
|
||||
|
||||
@@ -99,9 +99,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
return serialize($this->__serialize());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
/** @return array<string, mixed> */
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [
|
||||
@@ -122,9 +120,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
|
||||
$this->__unserialize(unserialize($serialized));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
/** @param array<string, mixed> $data */
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
$this->_sequenceName = $data['sequenceName'];
|
||||
|
||||
@@ -423,6 +423,10 @@ abstract class AbstractHydrator
|
||||
$type = $cacheKeyInfo['type'];
|
||||
$value = $type->convertToPHPValue($value, $this->_platform);
|
||||
|
||||
if ($value !== null && isset($cacheKeyInfo['enumType'])) {
|
||||
$value = $this->buildEnum($value, $cacheKeyInfo['enumType']);
|
||||
}
|
||||
|
||||
$rowData['newObjects'][$objIndex]['class'] = $cacheKeyInfo['class'];
|
||||
$rowData['newObjects'][$objIndex]['args'][$argIndex] = $value;
|
||||
break;
|
||||
@@ -431,16 +435,8 @@ abstract class AbstractHydrator
|
||||
$type = $cacheKeyInfo['type'];
|
||||
$value = $type->convertToPHPValue($value, $this->_platform);
|
||||
|
||||
// Reimplement ReflectionEnumProperty code
|
||||
if ($value !== null && isset($cacheKeyInfo['enumType'])) {
|
||||
$enumType = $cacheKeyInfo['enumType'];
|
||||
if (is_array($value)) {
|
||||
$value = array_map(static function ($value) use ($enumType): BackedEnum {
|
||||
return $enumType::from($value);
|
||||
}, $value);
|
||||
} else {
|
||||
$value = $enumType::from($value);
|
||||
}
|
||||
$value = $this->buildEnum($value, $cacheKeyInfo['enumType']);
|
||||
}
|
||||
|
||||
$rowData['scalars'][$fieldName] = $value;
|
||||
@@ -468,6 +464,10 @@ abstract class AbstractHydrator
|
||||
break;
|
||||
}
|
||||
|
||||
if ($value !== null && isset($cacheKeyInfo['enumType'])) {
|
||||
$value = $this->buildEnum($value, $cacheKeyInfo['enumType']);
|
||||
}
|
||||
|
||||
$rowData['data'][$dqlAlias][$fieldName] = $type
|
||||
? $type->convertToPHPValue($value, $this->_platform)
|
||||
: $value;
|
||||
@@ -551,6 +551,7 @@ abstract class AbstractHydrator
|
||||
'fieldName' => $fieldName,
|
||||
'type' => Type::getType($fieldMapping['type']),
|
||||
'dqlAlias' => $ownerMap,
|
||||
'enumType' => $this->_rsm->enumMappings[$key] ?? null,
|
||||
];
|
||||
|
||||
// the current discriminator value must be saved in order to disambiguate fields hydration,
|
||||
@@ -580,6 +581,7 @@ abstract class AbstractHydrator
|
||||
'argIndex' => $mapping['argIndex'],
|
||||
'objIndex' => $mapping['objIndex'],
|
||||
'class' => new ReflectionClass($mapping['className']),
|
||||
'enumType' => $this->_rsm->enumMappings[$key] ?? null,
|
||||
];
|
||||
|
||||
case isset($this->_rsm->scalarMappings[$key], $this->_hints[LimitSubqueryWalker::FORCE_DBAL_TYPE_CONVERSION]):
|
||||
@@ -688,4 +690,21 @@ abstract class AbstractHydrator
|
||||
|
||||
$this->_em->getUnitOfWork()->registerManaged($entity, $id, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @param class-string<BackedEnum> $enumType
|
||||
*
|
||||
* @return BackedEnum|array<BackedEnum>
|
||||
*/
|
||||
private function buildEnum($value, string $enumType)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return array_map(static function ($value) use ($enumType): BackedEnum {
|
||||
return $enumType::from($value);
|
||||
}, $value);
|
||||
}
|
||||
|
||||
return $enumType::from($value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,7 @@ use function sprintf;
|
||||
|
||||
class HydrationException extends ORMException
|
||||
{
|
||||
/**
|
||||
* @return HydrationException
|
||||
*/
|
||||
/** @return HydrationException */
|
||||
public static function nonUniqueResult()
|
||||
{
|
||||
return new self('The result returned by the query was not unique.');
|
||||
@@ -83,18 +81,17 @@ class HydrationException extends ORMException
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $discrValue
|
||||
* @param string[] $discrMap
|
||||
* @psalm-param array<string, string> $discrMap
|
||||
* @param string $discrValue
|
||||
* @param list<int|string> $discrValues
|
||||
*
|
||||
* @return HydrationException
|
||||
*/
|
||||
public static function invalidDiscriminatorValue($discrValue, $discrMap)
|
||||
public static function invalidDiscriminatorValue($discrValue, $discrValues)
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The discriminator value "%s" is invalid. It must be one of "%s".',
|
||||
$discrValue,
|
||||
implode('", "', $discrMap)
|
||||
implode('", "', $discrValues)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,7 @@ class IterableResult implements Iterator
|
||||
/** @var mixed[]|null */
|
||||
private $_current = null;
|
||||
|
||||
/**
|
||||
* @param AbstractHydrator $hydrator
|
||||
*/
|
||||
/** @param AbstractHydrator $hydrator */
|
||||
public function __construct($hydrator)
|
||||
{
|
||||
$this->_hydrator = $hydrator;
|
||||
@@ -65,27 +63,21 @@ class IterableResult implements Iterator
|
||||
return $this->_current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
/** @return mixed */
|
||||
#[ReturnTypeWillChange]
|
||||
public function current()
|
||||
{
|
||||
return $this->_current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
/** @return int */
|
||||
#[ReturnTypeWillChange]
|
||||
public function key()
|
||||
{
|
||||
return $this->_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
/** @return bool */
|
||||
#[ReturnTypeWillChange]
|
||||
public function valid()
|
||||
{
|
||||
|
||||
@@ -44,6 +44,9 @@ class ObjectHydrator extends AbstractHydrator
|
||||
/** @var mixed[] */
|
||||
private $initializedCollections = [];
|
||||
|
||||
/** @var array<string, PersistentCollection> */
|
||||
private $uninitializedCollections = [];
|
||||
|
||||
/** @var mixed[] */
|
||||
private $existingCollections = [];
|
||||
|
||||
@@ -112,10 +115,11 @@ class ObjectHydrator extends AbstractHydrator
|
||||
|
||||
parent::cleanup();
|
||||
|
||||
$this->identifierMap =
|
||||
$this->initializedCollections =
|
||||
$this->existingCollections =
|
||||
$this->resultPointers = [];
|
||||
$this->identifierMap =
|
||||
$this->initializedCollections =
|
||||
$this->uninitializedCollections =
|
||||
$this->existingCollections =
|
||||
$this->resultPointers = [];
|
||||
|
||||
if ($eagerLoad) {
|
||||
$this->_uow->triggerEagerLoads();
|
||||
@@ -126,10 +130,11 @@ class ObjectHydrator extends AbstractHydrator
|
||||
|
||||
protected function cleanupAfterRowIteration(): void
|
||||
{
|
||||
$this->identifierMap =
|
||||
$this->initializedCollections =
|
||||
$this->existingCollections =
|
||||
$this->resultPointers = [];
|
||||
$this->identifierMap =
|
||||
$this->initializedCollections =
|
||||
$this->uninitializedCollections =
|
||||
$this->existingCollections =
|
||||
$this->resultPointers = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,6 +153,12 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$coll->takeSnapshot();
|
||||
}
|
||||
|
||||
foreach ($this->uninitializedCollections as $coll) {
|
||||
if (! $coll->isInitialized()) {
|
||||
$coll->setInitialized(true);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -411,8 +422,8 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
} elseif (! $reflFieldValue) {
|
||||
$this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
|
||||
} elseif ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false) {
|
||||
$reflFieldValue->setInitialized(true);
|
||||
} elseif ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false && ! isset($this->uninitializedCollections[$oid . $relationField])) {
|
||||
$this->uninitializedCollections[$oid . $relationField] = $reflFieldValue;
|
||||
}
|
||||
} else {
|
||||
// PATH B: Single-valued association
|
||||
|
||||
@@ -13,9 +13,7 @@ use function method_exists;
|
||||
use function strtolower;
|
||||
use function strtoupper;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
/** @internal */
|
||||
trait SQLResultCasing
|
||||
{
|
||||
private function getSQLResultCasing(AbstractPlatform $platform, string $column): string
|
||||
|
||||
@@ -25,9 +25,7 @@ final class AssociationOverrides implements Annotation
|
||||
*/
|
||||
public $overrides = [];
|
||||
|
||||
/**
|
||||
* @param array<AssociationOverride>|AssociationOverride $overrides
|
||||
*/
|
||||
/** @param array<AssociationOverride>|AssociationOverride $overrides */
|
||||
public function __construct($overrides)
|
||||
{
|
||||
if (! is_array($overrides)) {
|
||||
|
||||
@@ -25,9 +25,7 @@ final class AttributeOverrides implements Annotation
|
||||
*/
|
||||
public $overrides = [];
|
||||
|
||||
/**
|
||||
* @param array<AttributeOverride>|AttributeOverride $overrides
|
||||
*/
|
||||
/** @param array<AttributeOverride>|AttributeOverride $overrides */
|
||||
public function __construct($overrides)
|
||||
{
|
||||
if (! is_array($overrides)) {
|
||||
|
||||
@@ -56,9 +56,7 @@ class AssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
/** @return $this */
|
||||
public function cascadeAll()
|
||||
{
|
||||
$this->mapping['cascade'] = ['ALL'];
|
||||
@@ -66,9 +64,7 @@ class AssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
/** @return $this */
|
||||
public function cascadePersist()
|
||||
{
|
||||
$this->mapping['cascade'][] = 'persist';
|
||||
@@ -76,9 +72,7 @@ class AssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
/** @return $this */
|
||||
public function cascadeRemove()
|
||||
{
|
||||
$this->mapping['cascade'][] = 'remove';
|
||||
@@ -86,9 +80,7 @@ class AssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
/** @return $this */
|
||||
public function cascadeMerge()
|
||||
{
|
||||
$this->mapping['cascade'][] = 'merge';
|
||||
@@ -96,9 +88,7 @@ class AssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
/** @return $this */
|
||||
public function cascadeDetach()
|
||||
{
|
||||
$this->mapping['cascade'][] = 'detach';
|
||||
@@ -106,9 +96,7 @@ class AssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
/** @return $this */
|
||||
public function cascadeRefresh()
|
||||
{
|
||||
$this->mapping['cascade'][] = 'refresh';
|
||||
@@ -116,9 +104,7 @@ class AssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
/** @return $this */
|
||||
public function fetchExtraLazy()
|
||||
{
|
||||
$this->mapping['fetch'] = ClassMetadata::FETCH_EXTRA_LAZY;
|
||||
@@ -126,9 +112,7 @@ class AssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
/** @return $this */
|
||||
public function fetchEager()
|
||||
{
|
||||
$this->mapping['fetch'] = ClassMetadata::FETCH_EAGER;
|
||||
@@ -136,9 +120,7 @@ class AssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
/** @return $this */
|
||||
public function fetchLazy()
|
||||
{
|
||||
$this->mapping['fetch'] = ClassMetadata::FETCH_LAZY;
|
||||
|
||||
@@ -4,9 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Builder;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
|
||||
use function get_class;
|
||||
|
||||
/**
|
||||
* Builder Object for ClassMetadata
|
||||
*
|
||||
@@ -19,12 +22,21 @@ class ClassMetadataBuilder
|
||||
|
||||
public function __construct(ClassMetadataInfo $cm)
|
||||
{
|
||||
if (! $cm instanceof ClassMetadata) {
|
||||
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.',
|
||||
get_class($cm),
|
||||
__METHOD__,
|
||||
ClassMetadata::class
|
||||
);
|
||||
}
|
||||
|
||||
$this->cm = $cm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadataInfo
|
||||
*/
|
||||
/** @return ClassMetadataInfo */
|
||||
public function getClassMetadata()
|
||||
{
|
||||
return $this->cm;
|
||||
|
||||
@@ -17,9 +17,7 @@ class EmbeddedBuilder
|
||||
/** @var mixed[] */
|
||||
private $mapping;
|
||||
|
||||
/**
|
||||
* @param mixed[] $mapping
|
||||
*/
|
||||
/** @param mixed[] $mapping */
|
||||
public function __construct(ClassMetadataBuilder $builder, array $mapping)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
|
||||
@@ -31,9 +31,7 @@ class FieldBuilder
|
||||
/** @var string|null */
|
||||
private $customIdGenerator;
|
||||
|
||||
/**
|
||||
* @param mixed[] $mapping
|
||||
*/
|
||||
/** @param mixed[] $mapping */
|
||||
public function __construct(ClassMetadataBuilder $builder, array $mapping)
|
||||
{
|
||||
$this->builder = $builder;
|
||||
|
||||
@@ -55,9 +55,7 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
/** @return ClassMetadataBuilder */
|
||||
public function build()
|
||||
{
|
||||
$mapping = $this->mapping;
|
||||
|
||||
@@ -35,9 +35,7 @@ class OneToManyAssociationBuilder extends AssociationBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadataBuilder
|
||||
*/
|
||||
/** @return ClassMetadataBuilder */
|
||||
public function build()
|
||||
{
|
||||
$mapping = $this->mapping;
|
||||
|
||||
@@ -33,6 +33,7 @@ use function class_exists;
|
||||
use function count;
|
||||
use function end;
|
||||
use function explode;
|
||||
use function get_class;
|
||||
use function in_array;
|
||||
use function is_subclass_of;
|
||||
use function str_contains;
|
||||
@@ -64,9 +65,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
/** @var mixed[] */
|
||||
private $embeddablesActiveNesting = [];
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
/** @return void */
|
||||
public function setEntityManager(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
@@ -225,7 +224,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
$this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
|
||||
}
|
||||
|
||||
if ($class->changeTrackingPolicy === ClassMetadataInfo::CHANGETRACKING_NOTIFY) {
|
||||
if ($class->changeTrackingPolicy === ClassMetadata::CHANGETRACKING_NOTIFY) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/8383',
|
||||
@@ -558,6 +557,18 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
|
||||
// Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
|
||||
if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/issues/8850',
|
||||
<<<'DEPRECATION'
|
||||
Context: Loading metadata for class %s
|
||||
Problem: Using the IDENTITY generator strategy with platform "%s" is deprecated and will not be possible in Doctrine ORM 3.0.
|
||||
Solution: Use the SEQUENCE generator strategy instead.
|
||||
DEPRECATION
|
||||
,
|
||||
$class->name,
|
||||
get_class($this->getTargetPlatform())
|
||||
);
|
||||
$columnName = $class->getSingleIdentifierColumnName();
|
||||
$quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
|
||||
$sequencePrefix = $class->getSequencePrefix($this->getTargetPlatform());
|
||||
@@ -646,9 +657,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return ClassMetadata::GENERATOR_TYPE_SEQUENCE|ClassMetadata::GENERATOR_TYPE_IDENTITY
|
||||
*/
|
||||
/** @psalm-return ClassMetadata::GENERATOR_TYPE_SEQUENCE|ClassMetadata::GENERATOR_TYPE_IDENTITY */
|
||||
private function determineIdGeneratorStrategy(AbstractPlatform $platform): int
|
||||
{
|
||||
if (
|
||||
|
||||
@@ -97,6 +97,51 @@ use const PHP_VERSION_ID;
|
||||
* 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,
|
||||
* }
|
||||
*/
|
||||
class ClassMetadataInfo implements ClassMetadata
|
||||
{
|
||||
@@ -519,7 +564,9 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*
|
||||
* @see discriminatorColumn
|
||||
*
|
||||
* @var mixed
|
||||
* @var array<int|string, string>
|
||||
*
|
||||
* @psalm-var array<int|string, class-string>
|
||||
*/
|
||||
public $discriminatorMap = [];
|
||||
|
||||
@@ -527,7 +574,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE
|
||||
* inheritance mappings.
|
||||
*
|
||||
* @psalm-var array<string, mixed>|null
|
||||
* @psalm-var array{name: string, fieldName: string, type: string, length?: int, columnDefinition?: string|null}|null
|
||||
*/
|
||||
public $discriminatorColumn;
|
||||
|
||||
@@ -543,10 +590,10 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* @var mixed[]
|
||||
* @psalm-var array{
|
||||
* name: string,
|
||||
* schema: string,
|
||||
* indexes: array,
|
||||
* uniqueConstraints: array,
|
||||
* options: array<string, mixed>,
|
||||
* schema?: string,
|
||||
* indexes?: array,
|
||||
* uniqueConstraints?: array,
|
||||
* options?: array<string, mixed>,
|
||||
* quoted?: bool
|
||||
* }
|
||||
*/
|
||||
@@ -619,7 +666,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* )
|
||||
* </pre>
|
||||
*
|
||||
* @psalm-var array<string, array<string, mixed>>
|
||||
* @psalm-var array<string, AssociationMapping>
|
||||
*/
|
||||
public $associationMappings = [];
|
||||
|
||||
@@ -669,8 +716,8 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
* @psalm-var array{sequenceName: string, allocationSize: string, initialValue: string, quoted?: mixed}
|
||||
* @var array<string, mixed>|null
|
||||
* @psalm-var array{sequenceName: string, allocationSize: string, initialValue: string, quoted?: mixed}|null
|
||||
* @todo Merge with tableGeneratorDefinition into generic generatorDefinition
|
||||
*/
|
||||
public $sequenceGeneratorDefinition;
|
||||
@@ -711,7 +758,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any).
|
||||
*
|
||||
* @var mixed
|
||||
* @var string|null
|
||||
*/
|
||||
public $versionField;
|
||||
|
||||
@@ -1381,7 +1428,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* the object model.
|
||||
*
|
||||
* @return mixed[] The mapping.
|
||||
* @psalm-return array<string, mixed>
|
||||
* @psalm-return AssociationMapping
|
||||
*
|
||||
* @throws MappingException
|
||||
*/
|
||||
@@ -1397,7 +1444,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* Gets all association mappings of the class.
|
||||
*
|
||||
* @psalm-return array<string, array<string, mixed>>
|
||||
* @psalm-return array<string, AssociationMapping>
|
||||
*/
|
||||
public function getAssociationMappings()
|
||||
{
|
||||
@@ -1873,9 +1920,9 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* originalClass: class-string,
|
||||
* joinColumns?: array{0: array{name: string, referencedColumnName: string}}|mixed,
|
||||
* id?: mixed,
|
||||
* sourceToTargetKeyColumns?: array,
|
||||
* joinColumnFieldNames?: array,
|
||||
* targetToSourceKeyColumns?: array<array-key>,
|
||||
* sourceToTargetKeyColumns?: array<string, string>,
|
||||
* joinColumnFieldNames?: array<string, string>,
|
||||
* targetToSourceKeyColumns?: array<string, string>,
|
||||
* orphanRemoval: bool
|
||||
* }
|
||||
*
|
||||
@@ -2276,9 +2323,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
return $this->generatorType !== self::GENERATOR_TYPE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
/** @return bool */
|
||||
public function isInheritanceTypeNone()
|
||||
{
|
||||
return $this->inheritanceType === self::INHERITANCE_TYPE_NONE;
|
||||
@@ -2331,6 +2376,8 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* Checks whether the class uses a sequence for id generation.
|
||||
*
|
||||
* @return bool TRUE if the class uses the SEQUENCE generator, FALSE otherwise.
|
||||
*
|
||||
* @psalm-assert-if-true !null $this->sequenceGeneratorDefinition
|
||||
*/
|
||||
public function isIdGeneratorSequence()
|
||||
{
|
||||
@@ -2760,7 +2807,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* Adds an association mapping without completing/validating it.
|
||||
* This is mainly used to add inherited association mappings to derived classes.
|
||||
*
|
||||
* @psalm-param array<string, mixed> $mapping
|
||||
* @psalm-param AssociationMapping $mapping
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -3168,7 +3215,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* @see getDiscriminatorColumn()
|
||||
*
|
||||
* @param mixed[]|null $columnDef
|
||||
* @psalm-param array<string, mixed>|null $columnDef
|
||||
* @psalm-param array{name: string|null, fieldName?: string, type?: string, length?: int, columnDefinition?: string|null}|null $columnDef
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -3201,9 +3248,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
/** @return array<string, mixed> */
|
||||
final public function getDiscriminatorColumn(): array
|
||||
{
|
||||
if ($this->discriminatorColumn === null) {
|
||||
@@ -3217,7 +3262,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* Sets the discriminator values used by this class.
|
||||
* Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
|
||||
*
|
||||
* @psalm-param array<string, class-string> $map
|
||||
* @param array<int|string, string> $map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -3231,9 +3276,8 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* Adds one entry of the discriminator map with a new class and corresponding name.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $className
|
||||
* @psalm-param class-string $className
|
||||
* @param int|string $name
|
||||
* @param string $className
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -3517,7 +3561,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* Sets the name of the field that is to be used for versioning if this class is
|
||||
* versioned for optimistic locking.
|
||||
*
|
||||
* @param string $versionField
|
||||
* @param string|null $versionField
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -3707,7 +3751,6 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
/**
|
||||
* @param string|null $className
|
||||
* @psalm-param string|class-string|null $className
|
||||
*
|
||||
* @return string|null null if the input value is null
|
||||
* @psalm-return class-string|null
|
||||
@@ -3800,9 +3843,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MappingException
|
||||
*/
|
||||
/** @throws MappingException */
|
||||
private function assertFieldNotMapped(string $fieldName): void
|
||||
{
|
||||
if (
|
||||
@@ -3854,9 +3895,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
return $sequencePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param array<string, mixed> $mapping
|
||||
*/
|
||||
/** @psalm-param array<string, mixed> $mapping */
|
||||
private function assertMappingOrderBy(array $mapping): void
|
||||
{
|
||||
if (isset($mapping['orderBy']) && ! is_array($mapping['orderBy'])) {
|
||||
@@ -3864,9 +3903,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param class-string $class
|
||||
*/
|
||||
/** @psalm-param class-string $class */
|
||||
private function getAccessibleProperty(ReflectionService $reflService, string $class, string $field): ?ReflectionProperty
|
||||
{
|
||||
$reflectionProperty = $reflService->getAccessibleProperty($class, $field);
|
||||
|
||||
@@ -54,6 +54,9 @@ class DefaultNamingStrategy implements NamingStrategy
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $propertyName
|
||||
* @param class-string $className
|
||||
*/
|
||||
public function joinColumnName($propertyName, $className = null)
|
||||
{
|
||||
|
||||
@@ -15,16 +15,10 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
final class DiscriminatorMap implements Annotation
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
* @psalm-var array<string, class-string>
|
||||
*/
|
||||
/** @var array<int|string, string> */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* @param array<string, string> $value
|
||||
* @psalm-param array<string, class-string> $value
|
||||
*/
|
||||
/** @param array<int|string, string> $value */
|
||||
public function __construct(array $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
@@ -10,11 +10,10 @@ use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Mapping;
|
||||
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\Driver\ColocatedMappingDriver;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
@@ -32,7 +31,7 @@ use function is_numeric;
|
||||
/**
|
||||
* The AnnotationDriver reads the mapping metadata from docblock annotations.
|
||||
*/
|
||||
class AnnotationDriver implements MappingDriver
|
||||
class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
{
|
||||
use ColocatedMappingDriver;
|
||||
|
||||
@@ -70,10 +69,14 @@ class AnnotationDriver implements MappingDriver
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
public function loadMetadataForClass($className, PersistenceClassMetadata $metadata)
|
||||
{
|
||||
assert($metadata instanceof Mapping\ClassMetadata);
|
||||
$class = $metadata->getReflectionClass()
|
||||
// this happens when running annotation driver in combination with
|
||||
// static reflection services. This is not the nicest fix
|
||||
@@ -299,7 +302,7 @@ class AnnotationDriver implements MappingDriver
|
||||
constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAnnot->value)
|
||||
);
|
||||
|
||||
if ($metadata->inheritanceType !== ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
|
||||
if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||
// Evaluate DiscriminatorColumn annotation
|
||||
if (isset($classAnnotations[Mapping\DiscriminatorColumn::class])) {
|
||||
$discrColumnAnnot = $classAnnotations[Mapping\DiscriminatorColumn::class];
|
||||
@@ -544,7 +547,7 @@ class AnnotationDriver implements MappingDriver
|
||||
private function loadRelationShipMapping(
|
||||
ReflectionProperty $property,
|
||||
array &$mapping,
|
||||
ClassMetadata $metadata,
|
||||
PersistenceClassMetadata $metadata,
|
||||
array $joinColumns,
|
||||
string $className
|
||||
): void {
|
||||
@@ -610,6 +613,10 @@ class AnnotationDriver implements MappingDriver
|
||||
'schema' => $joinTableAnnot->schema,
|
||||
];
|
||||
|
||||
if ($joinTableAnnot->options) {
|
||||
$joinTable['options'] = $joinTableAnnot->options;
|
||||
}
|
||||
|
||||
foreach ($joinTableAnnot->joinColumns as $joinColumn) {
|
||||
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
|
||||
}
|
||||
@@ -648,7 +655,7 @@ class AnnotationDriver implements MappingDriver
|
||||
/**
|
||||
* Attempts to resolve the fetch mode.
|
||||
*
|
||||
* @psalm-return \Doctrine\ORM\Mapping\ClassMetadata::FETCH_* The fetch mode as defined in ClassMetadata.
|
||||
* @psalm-return ClassMetadata::FETCH_* The fetch mode as defined in ClassMetadata.
|
||||
*
|
||||
* @throws MappingException If the fetch mode is not valid.
|
||||
*/
|
||||
@@ -664,7 +671,7 @@ class AnnotationDriver implements MappingDriver
|
||||
/**
|
||||
* Attempts to resolve the generated mode.
|
||||
*
|
||||
* @psalm-return ClassMetadataInfo::GENERATED_*
|
||||
* @psalm-return ClassMetadata::GENERATED_*
|
||||
*
|
||||
* @throws MappingException If the fetch mode is not valid.
|
||||
*/
|
||||
@@ -735,12 +742,13 @@ class AnnotationDriver implements MappingDriver
|
||||
* nullable: bool,
|
||||
* onDelete: mixed,
|
||||
* columnDefinition: string|null,
|
||||
* referencedColumnName: string
|
||||
* referencedColumnName: string,
|
||||
* options?: array<string, mixed>
|
||||
* }
|
||||
*/
|
||||
private function joinColumnToArray(Mapping\JoinColumn $joinColumn): array
|
||||
{
|
||||
return [
|
||||
$mapping = [
|
||||
'name' => $joinColumn->name,
|
||||
'unique' => $joinColumn->unique,
|
||||
'nullable' => $joinColumn->nullable,
|
||||
@@ -748,6 +756,12 @@ class AnnotationDriver implements MappingDriver
|
||||
'columnDefinition' => $joinColumn->columnDefinition,
|
||||
'referencedColumnName' => $joinColumn->referencedColumnName,
|
||||
];
|
||||
|
||||
if ($joinColumn->options) {
|
||||
$mapping['options'] = $joinColumn->options;
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -764,7 +778,7 @@ class AnnotationDriver implements MappingDriver
|
||||
* precision: int,
|
||||
* notInsertable?: bool,
|
||||
* notUpdateble?: bool,
|
||||
* generated?: ClassMetadataInfo::GENERATED_*,
|
||||
* generated?: ClassMetadata::GENERATED_*,
|
||||
* enumType?: class-string,
|
||||
* options?: mixed[],
|
||||
* columnName?: string,
|
||||
|
||||
@@ -8,11 +8,10 @@ use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Mapping;
|
||||
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\Driver\ColocatedMappingDriver;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
|
||||
use LogicException;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
@@ -27,7 +26,7 @@ use function sprintf;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
class AttributeDriver implements MappingDriver
|
||||
class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
{
|
||||
use ColocatedMappingDriver;
|
||||
|
||||
@@ -47,9 +46,7 @@ class AttributeDriver implements MappingDriver
|
||||
*/
|
||||
protected $reader;
|
||||
|
||||
/**
|
||||
* @param array<string> $paths
|
||||
*/
|
||||
/** @param array<string> $paths */
|
||||
public function __construct(array $paths)
|
||||
{
|
||||
if (PHP_VERSION_ID < 80000) {
|
||||
@@ -99,11 +96,20 @@ class AttributeDriver implements MappingDriver
|
||||
return true;
|
||||
}
|
||||
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata): void
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public function loadMetadataForClass($className, PersistenceClassMetadata $metadata): void
|
||||
{
|
||||
assert($metadata instanceof ClassMetadataInfo);
|
||||
|
||||
$reflectionClass = $metadata->getReflectionClass();
|
||||
$reflectionClass = $metadata->getReflectionClass()
|
||||
// this happens when running annotation driver in combination with
|
||||
// static reflection services. This is not the nicest fix
|
||||
?? new ReflectionClass($metadata->name);
|
||||
|
||||
$classAttributes = $this->reader->getClassAnnotations($reflectionClass);
|
||||
|
||||
@@ -239,17 +245,17 @@ class AttributeDriver implements MappingDriver
|
||||
constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAttribute->value)
|
||||
);
|
||||
|
||||
if ($metadata->inheritanceType !== Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||
if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||
// Evaluate DiscriminatorColumn annotation
|
||||
if (isset($classAttributes[Mapping\DiscriminatorColumn::class])) {
|
||||
$discrColumnAttribute = $classAttributes[Mapping\DiscriminatorColumn::class];
|
||||
|
||||
$metadata->setDiscriminatorColumn(
|
||||
[
|
||||
'name' => $discrColumnAttribute->name,
|
||||
'type' => $discrColumnAttribute->type ?: 'string',
|
||||
'length' => $discrColumnAttribute->length ?: 255,
|
||||
'columnDefinition' => $discrColumnAttribute->columnDefinition,
|
||||
'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,
|
||||
]
|
||||
);
|
||||
} else {
|
||||
@@ -407,6 +413,10 @@ class AttributeDriver implements MappingDriver
|
||||
'name' => $joinTableAttribute->name,
|
||||
'schema' => $joinTableAttribute->schema,
|
||||
];
|
||||
|
||||
if ($joinTableAttribute->options) {
|
||||
$joinTable['options'] = $joinTableAttribute->options;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->reader->getPropertyAnnotationCollection($property, Mapping\JoinColumn::class) as $joinColumn) {
|
||||
@@ -492,7 +502,7 @@ class AttributeDriver implements MappingDriver
|
||||
|
||||
// Check for `fetch`
|
||||
if ($associationOverride->fetch) {
|
||||
$override['fetch'] = constant(Mapping\ClassMetadata::class . '::FETCH_' . $associationOverride->fetch);
|
||||
$override['fetch'] = constant(ClassMetadata::class . '::FETCH_' . $associationOverride->fetch);
|
||||
}
|
||||
|
||||
$metadata->setAssociationOverride($fieldName, $override);
|
||||
@@ -559,7 +569,7 @@ class AttributeDriver implements MappingDriver
|
||||
* @param string $className The class name.
|
||||
* @param string $fetchMode The fetch mode.
|
||||
*
|
||||
* @return int The fetch mode as defined in ClassMetadata.
|
||||
* @return ClassMetadata::FETCH_* The fetch mode as defined in ClassMetadata.
|
||||
*
|
||||
* @throws MappingException If the fetch mode is not valid.
|
||||
*/
|
||||
@@ -645,12 +655,13 @@ class AttributeDriver implements MappingDriver
|
||||
* nullable: bool,
|
||||
* onDelete: mixed,
|
||||
* columnDefinition: string|null,
|
||||
* referencedColumnName: string
|
||||
* referencedColumnName: string,
|
||||
* options?: array<string, mixed>
|
||||
* }
|
||||
*/
|
||||
private function joinColumnToArray($joinColumn): array
|
||||
{
|
||||
return [
|
||||
$mapping = [
|
||||
'name' => $joinColumn->name,
|
||||
'unique' => $joinColumn->unique,
|
||||
'nullable' => $joinColumn->nullable,
|
||||
@@ -658,6 +669,12 @@ class AttributeDriver implements MappingDriver
|
||||
'columnDefinition' => $joinColumn->columnDefinition,
|
||||
'referencedColumnName' => $joinColumn->referencedColumnName,
|
||||
];
|
||||
|
||||
if ($joinColumn->options) {
|
||||
$mapping['options'] = $joinColumn->options;
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,9 +17,7 @@ use function is_string;
|
||||
use function is_subclass_of;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
/** @internal */
|
||||
final class AttributeReader
|
||||
{
|
||||
/** @var array<class-string<Annotation>,bool> */
|
||||
@@ -134,9 +132,7 @@ final class AttributeReader
|
||||
return $instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<Annotation> $attributeClassName
|
||||
*/
|
||||
/** @param class-string<Annotation> $attributeClassName */
|
||||
private function isRepeatable(string $attributeClassName): bool
|
||||
{
|
||||
if (isset($this->isRepeatableAttribute[$attributeClassName])) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\Persistence\Mapping\Driver\AnnotationDriver as PersistenceAnnotationDriver;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
|
||||
|
||||
use function class_exists;
|
||||
|
||||
if (! class_exists(PersistenceAnnotationDriver::class)) {
|
||||
/** @internal This class will be removed in ORM 3.0. */
|
||||
abstract class CompatibilityAnnotationDriver implements MappingDriver
|
||||
{
|
||||
}
|
||||
} else {
|
||||
/** @internal This class will be removed in ORM 3.0. */
|
||||
abstract class CompatibilityAnnotationDriver extends PersistenceAnnotationDriver
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -6,23 +6,27 @@ namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\DBAL\Schema\AbstractSchemaManager;
|
||||
use Doctrine\DBAL\Schema\Column;
|
||||
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use Doctrine\DBAL\Schema\Table;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\Inflector\Inflector;
|
||||
use Doctrine\Inflector\InflectorFactory;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
|
||||
use InvalidArgumentException;
|
||||
|
||||
use function array_diff;
|
||||
use function array_keys;
|
||||
use function array_merge;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function current;
|
||||
use function get_class;
|
||||
use function in_array;
|
||||
use function preg_replace;
|
||||
use function sort;
|
||||
@@ -35,6 +39,20 @@ use function strtolower;
|
||||
*/
|
||||
class DatabaseDriver implements MappingDriver
|
||||
{
|
||||
/**
|
||||
* Replacement for {@see Types::ARRAY}.
|
||||
*
|
||||
* To be removed as soon as support for DBAL 3 is dropped.
|
||||
*/
|
||||
private const ARRAY = 'array';
|
||||
|
||||
/**
|
||||
* Replacement for {@see Types::OBJECT}.
|
||||
*
|
||||
* To be removed as soon as support for DBAL 3 is dropped.
|
||||
*/
|
||||
private const OBJECT = 'object';
|
||||
|
||||
/**
|
||||
* Replacement for {@see Types::JSON_ARRAY}.
|
||||
*
|
||||
@@ -166,9 +184,25 @@ class DatabaseDriver implements MappingDriver
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
public function loadMetadataForClass($className, PersistenceClassMetadata $metadata)
|
||||
{
|
||||
if (! $metadata instanceof ClassMetadata) {
|
||||
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.',
|
||||
get_class($metadata),
|
||||
__METHOD__,
|
||||
ClassMetadata::class
|
||||
);
|
||||
}
|
||||
|
||||
$this->reverseEngineerMappingFromDatabase();
|
||||
|
||||
if (! isset($this->classToTableNames[$className])) {
|
||||
@@ -251,27 +285,18 @@ class DatabaseDriver implements MappingDriver
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MappingException
|
||||
*/
|
||||
/** @throws MappingException */
|
||||
private function reverseEngineerMappingFromDatabase(): void
|
||||
{
|
||||
if ($this->tables !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tables = [];
|
||||
|
||||
foreach ($this->_sm->listTableNames() as $tableName) {
|
||||
$tables[$tableName] = $this->_sm->listTableDetails($tableName);
|
||||
}
|
||||
|
||||
$this->tables = $this->manyToManyTables = $this->classToTableNames = [];
|
||||
|
||||
foreach ($tables as $tableName => $table) {
|
||||
$foreignKeys = $this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()
|
||||
? $table->getForeignKeys()
|
||||
: [];
|
||||
foreach ($this->_sm->listTables() as $table) {
|
||||
$tableName = $table->getName();
|
||||
$foreignKeys = $table->getForeignKeys();
|
||||
|
||||
$allForeignKeyColumns = [];
|
||||
|
||||
@@ -281,7 +306,7 @@ class DatabaseDriver implements MappingDriver
|
||||
|
||||
if (! $table->hasPrimaryKey()) {
|
||||
throw new MappingException(
|
||||
'Table ' . $table->getName() . ' has no primary key. Doctrine does not ' .
|
||||
'Table ' . $tableName . ' has no primary key. Doctrine does not ' .
|
||||
"support reverse engineering from tables that don't have a primary key."
|
||||
);
|
||||
}
|
||||
@@ -335,7 +360,7 @@ class DatabaseDriver implements MappingDriver
|
||||
$tableName = $metadata->table['name'];
|
||||
$columns = $this->tables[$tableName]->getColumns();
|
||||
$primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]);
|
||||
$foreignKeys = $this->getTableForeignKeys($this->tables[$tableName]);
|
||||
$foreignKeys = $this->tables[$tableName]->getForeignKeys();
|
||||
$allForeignKeys = [];
|
||||
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
@@ -362,7 +387,7 @@ class DatabaseDriver implements MappingDriver
|
||||
|
||||
// We need to check for the columns here, because we might have associations as id as well.
|
||||
if ($ids && count($primaryKeys) === 1) {
|
||||
$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO);
|
||||
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO);
|
||||
}
|
||||
|
||||
foreach ($fieldMappings as $fieldMapping) {
|
||||
@@ -395,17 +420,17 @@ class DatabaseDriver implements MappingDriver
|
||||
$fieldMapping = [
|
||||
'fieldName' => $this->getFieldNameForColumn($tableName, $column->getName(), false),
|
||||
'columnName' => $column->getName(),
|
||||
'type' => $column->getType()->getName(),
|
||||
'type' => Type::getTypeRegistry()->lookupName($column->getType()),
|
||||
'nullable' => ! $column->getNotnull(),
|
||||
];
|
||||
|
||||
// Type specific elements
|
||||
switch ($fieldMapping['type']) {
|
||||
case Types::ARRAY:
|
||||
case self::ARRAY:
|
||||
case Types::BLOB:
|
||||
case Types::GUID:
|
||||
case self::JSON_ARRAY:
|
||||
case Types::OBJECT:
|
||||
case self::OBJECT:
|
||||
case Types::SIMPLE_ARRAY:
|
||||
case Types::STRING:
|
||||
case Types::TEXT:
|
||||
@@ -448,9 +473,11 @@ class DatabaseDriver implements MappingDriver
|
||||
*/
|
||||
private function buildToOneAssociationMappings(ClassMetadataInfo $metadata)
|
||||
{
|
||||
assert($this->tables !== null);
|
||||
|
||||
$tableName = $metadata->table['name'];
|
||||
$primaryKeys = $this->getTablePrimaryKeys($this->tables[$tableName]);
|
||||
$foreignKeys = $this->getTableForeignKeys($this->tables[$tableName]);
|
||||
$foreignKeys = $this->tables[$tableName]->getForeignKeys();
|
||||
|
||||
foreach ($foreignKeys as $foreignKey) {
|
||||
$foreignTableName = $foreignKey->getForeignTableName();
|
||||
@@ -486,19 +513,6 @@ class DatabaseDriver implements MappingDriver
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve schema table definition foreign keys.
|
||||
*
|
||||
* @return ForeignKeyConstraint[]
|
||||
* @psalm-return array<string, ForeignKeyConstraint>
|
||||
*/
|
||||
private function getTableForeignKeys(Table $table): array
|
||||
{
|
||||
return $this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()
|
||||
? $table->getForeignKeys()
|
||||
: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve schema table definition primary keys.
|
||||
*
|
||||
|
||||
@@ -15,9 +15,7 @@ use Doctrine\Persistence\Mapping\Driver\PHPDriver as CommonPHPDriver;
|
||||
*/
|
||||
class PHPDriver extends CommonPHPDriver
|
||||
{
|
||||
/**
|
||||
* @param string|string[]|FileLocator $locator
|
||||
*/
|
||||
/** @param string|string[]|FileLocator $locator */
|
||||
public function __construct($locator)
|
||||
{
|
||||
Deprecation::trigger(
|
||||
|
||||
@@ -5,11 +5,13 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata as Metadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\Driver\FileDriver;
|
||||
use DOMDocument;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use SimpleXMLElement;
|
||||
@@ -22,6 +24,9 @@ use function explode;
|
||||
use function extension_loaded;
|
||||
use function file_get_contents;
|
||||
use function in_array;
|
||||
use function libxml_clear_errors;
|
||||
use function libxml_get_errors;
|
||||
use function libxml_use_internal_errors;
|
||||
use function simplexml_load_string;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
@@ -36,10 +41,13 @@ class XmlDriver extends FileDriver
|
||||
{
|
||||
public const DEFAULT_FILE_EXTENSION = '.dcm.xml';
|
||||
|
||||
/** @var bool */
|
||||
private $isXsdValidationEnabled;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
|
||||
public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION, bool $isXsdValidationEnabled = false)
|
||||
{
|
||||
if (! extension_loaded('simplexml')) {
|
||||
throw new LogicException(sprintf(
|
||||
@@ -48,13 +56,37 @@ class XmlDriver extends FileDriver
|
||||
));
|
||||
}
|
||||
|
||||
if (! $isXsdValidationEnabled) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/6728',
|
||||
sprintf(
|
||||
'Using XML mapping driver with XSD validation disabled is deprecated'
|
||||
. ' and will not be supported in Doctrine ORM 3.0.'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ($isXsdValidationEnabled && ! extension_loaded('dom')) {
|
||||
throw new LogicException(sprintf(
|
||||
'XSD validation cannot be enabled because the DOM extension is missing.'
|
||||
));
|
||||
}
|
||||
|
||||
$this->isXsdValidationEnabled = $isXsdValidationEnabled;
|
||||
|
||||
parent::__construct($locator, $fileExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
public function loadMetadataForClass($className, PersistenceClassMetadata $metadata)
|
||||
{
|
||||
$xmlRoot = $this->getElement($className);
|
||||
assert($xmlRoot instanceof SimpleXMLElement);
|
||||
@@ -168,7 +200,7 @@ class XmlDriver extends FileDriver
|
||||
$inheritanceType = (string) $xmlRoot['inheritance-type'];
|
||||
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType));
|
||||
|
||||
if ($metadata->inheritanceType !== Metadata::INHERITANCE_TYPE_NONE) {
|
||||
if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||
// Evaluate <discriminator-column...>
|
||||
if (isset($xmlRoot->{'discriminator-column'})) {
|
||||
$discrColumn = $xmlRoot->{'discriminator-column'};
|
||||
@@ -176,7 +208,7 @@ class XmlDriver extends FileDriver
|
||||
[
|
||||
'name' => isset($discrColumn['name']) ? (string) $discrColumn['name'] : null,
|
||||
'type' => isset($discrColumn['type']) ? (string) $discrColumn['type'] : 'string',
|
||||
'length' => isset($discrColumn['length']) ? (string) $discrColumn['length'] : 255,
|
||||
'length' => isset($discrColumn['length']) ? (int) $discrColumn['length'] : 255,
|
||||
'columnDefinition' => isset($discrColumn['column-definition']) ? (string) $discrColumn['column-definition'] : null,
|
||||
]
|
||||
);
|
||||
@@ -351,7 +383,7 @@ class XmlDriver extends FileDriver
|
||||
}
|
||||
|
||||
if (isset($idElement['length'])) {
|
||||
$mapping['length'] = (string) $idElement['length'];
|
||||
$mapping['length'] = (int) $idElement['length'];
|
||||
}
|
||||
|
||||
if (isset($idElement['column'])) {
|
||||
@@ -584,6 +616,10 @@ class XmlDriver extends FileDriver
|
||||
$joinTable['schema'] = (string) $joinTableElement['schema'];
|
||||
}
|
||||
|
||||
if (isset($joinTableElement->options)) {
|
||||
$joinTable['options'] = $this->parseOptions($joinTableElement->options->children());
|
||||
}
|
||||
|
||||
foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
|
||||
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
|
||||
}
|
||||
@@ -663,6 +699,10 @@ class XmlDriver extends FileDriver
|
||||
'schema' => (string) $joinTableElement['schema'],
|
||||
];
|
||||
|
||||
if (isset($joinTableElement->options)) {
|
||||
$joinTable['options'] = $this->parseOptions($joinTableElement->options->children());
|
||||
}
|
||||
|
||||
if (isset($joinTableElement->{'join-columns'})) {
|
||||
foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
|
||||
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
|
||||
@@ -685,7 +725,7 @@ class XmlDriver extends FileDriver
|
||||
|
||||
// Check for `fetch`
|
||||
if (isset($overrideElement['fetch'])) {
|
||||
$override['fetch'] = constant(Metadata::class . '::FETCH_' . (string) $overrideElement['fetch']);
|
||||
$override['fetch'] = constant(ClassMetadata::class . '::FETCH_' . (string) $overrideElement['fetch']);
|
||||
}
|
||||
|
||||
$metadata->setAssociationOverride($fieldName, $override);
|
||||
@@ -767,7 +807,8 @@ class XmlDriver extends FileDriver
|
||||
* unique?: bool,
|
||||
* nullable?: bool,
|
||||
* onDelete?: string,
|
||||
* columnDefinition?: string
|
||||
* columnDefinition?: string,
|
||||
* options?: mixed[]
|
||||
* }
|
||||
*/
|
||||
private function joinColumnToArray(SimpleXMLElement $joinColumnElement): array
|
||||
@@ -793,6 +834,10 @@ class XmlDriver extends FileDriver
|
||||
$joinColumn['columnDefinition'] = (string) $joinColumnElement['column-definition'];
|
||||
}
|
||||
|
||||
if (isset($joinColumnElement['options'])) {
|
||||
$joinColumn['options'] = $this->parseOptions($joinColumnElement['options']->children());
|
||||
}
|
||||
|
||||
return $joinColumn;
|
||||
}
|
||||
|
||||
@@ -935,6 +980,7 @@ class XmlDriver extends FileDriver
|
||||
*/
|
||||
protected function loadMappingFile($file)
|
||||
{
|
||||
$this->validateMapping($file);
|
||||
$result = [];
|
||||
// Note: we do not use `simplexml_load_file()` because of https://bugs.php.net/bug.php?id=62577
|
||||
$xmlElement = simplexml_load_string(file_get_contents($file));
|
||||
@@ -962,6 +1008,27 @@ class XmlDriver extends FileDriver
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function validateMapping(string $file): void
|
||||
{
|
||||
if (! $this->isXsdValidationEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$backedUpErrorSetting = libxml_use_internal_errors(true);
|
||||
|
||||
try {
|
||||
$document = new DOMDocument();
|
||||
$document->load($file);
|
||||
|
||||
if (! $document->schemaValidate(__DIR__ . '/../../../../../doctrine-mapping.xsd')) {
|
||||
throw MappingException::fromLibXmlErrors(libxml_get_errors());
|
||||
}
|
||||
} finally {
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($backedUpErrorSetting);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $element
|
||||
*
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata as Metadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\ClassMetadata as PersistenceClassMetadata;
|
||||
use Doctrine\Persistence\Mapping\Driver\FileDriver;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
@@ -60,8 +60,13 @@ class YamlDriver extends FileDriver
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
public function loadMetadataForClass($className, PersistenceClassMetadata $metadata)
|
||||
{
|
||||
$element = $this->getElement($className);
|
||||
|
||||
@@ -186,7 +191,7 @@ class YamlDriver extends FileDriver
|
||||
if (isset($element['inheritanceType'])) {
|
||||
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . strtoupper($element['inheritanceType'])));
|
||||
|
||||
if ($metadata->inheritanceType !== Metadata::INHERITANCE_TYPE_NONE) {
|
||||
if ($metadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||
// Evaluate discriminatorColumn
|
||||
if (isset($element['discriminatorColumn'])) {
|
||||
$discrColumn = $element['discriminatorColumn'];
|
||||
@@ -194,7 +199,7 @@ class YamlDriver extends FileDriver
|
||||
[
|
||||
'name' => isset($discrColumn['name']) ? (string) $discrColumn['name'] : null,
|
||||
'type' => isset($discrColumn['type']) ? (string) $discrColumn['type'] : 'string',
|
||||
'length' => isset($discrColumn['length']) ? (string) $discrColumn['length'] : 255,
|
||||
'length' => isset($discrColumn['length']) ? (int) $discrColumn['length'] : 255,
|
||||
'columnDefinition' => isset($discrColumn['columnDefinition']) ? (string) $discrColumn['columnDefinition'] : null,
|
||||
]
|
||||
);
|
||||
@@ -683,7 +688,7 @@ class YamlDriver extends FileDriver
|
||||
|
||||
// Check for `fetch`
|
||||
if (isset($associationOverrideElement['fetch'])) {
|
||||
$override['fetch'] = constant(Metadata::class . '::FETCH_' . $associationOverrideElement['fetch']);
|
||||
$override['fetch'] = constant(ClassMetadata::class . '::FETCH_' . $associationOverrideElement['fetch']);
|
||||
}
|
||||
|
||||
$metadata->setAssociationOverride($fieldName, $override);
|
||||
|
||||
@@ -12,22 +12,21 @@ use Doctrine\ORM\EntityRepository;
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("CLASS")
|
||||
* @template T of object
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
final class Entity implements Annotation
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
* @psalm-var class-string<EntityRepository>|null
|
||||
* @psalm-var class-string<EntityRepository<T>>|null
|
||||
*/
|
||||
public $repositoryClass;
|
||||
|
||||
/** @var bool */
|
||||
public $readOnly = false;
|
||||
|
||||
/**
|
||||
* @psalm-param class-string<EntityRepository>|null $repositoryClass
|
||||
*/
|
||||
/** @psalm-param class-string<EntityRepository<T>>|null $repositoryClass */
|
||||
public function __construct(?string $repositoryClass = null, bool $readOnly = false)
|
||||
{
|
||||
$this->repositoryClass = $repositoryClass;
|
||||
|
||||
@@ -12,7 +12,7 @@ interface EntityListenerResolver
|
||||
/**
|
||||
* Clear all instances from the set, or a specific instance when given its identifier.
|
||||
*
|
||||
* @param string $className May be any arbitrary string. Name kept for BC only.
|
||||
* @param string|null $className May be any arbitrary string. Name kept for BC only.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -31,6 +31,8 @@ interface EntityListenerResolver
|
||||
* Register a entity listener instance.
|
||||
*
|
||||
* @param object $object An entity listener
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($object);
|
||||
}
|
||||
|
||||
@@ -25,9 +25,7 @@ final class EntityListeners implements Annotation
|
||||
*/
|
||||
public $value = [];
|
||||
|
||||
/**
|
||||
* @param array<string> $value
|
||||
*/
|
||||
/** @param array<string> $value */
|
||||
public function __construct(array $value = [])
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
@@ -16,9 +16,7 @@ final class InvalidCustomGenerator extends ORMException
|
||||
return new self('Cannot instantiate custom generator, no class has been defined');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $definition
|
||||
*/
|
||||
/** @param mixed[] $definition */
|
||||
public static function onMissingClass(array $definition): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
|
||||
@@ -35,6 +35,12 @@ final class InverseJoinColumn implements Annotation
|
||||
*/
|
||||
public $fieldName;
|
||||
|
||||
/** @var array<string, mixed> */
|
||||
public $options = [];
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $options
|
||||
*/
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
string $referencedColumnName = 'id',
|
||||
@@ -42,7 +48,8 @@ final class InverseJoinColumn implements Annotation
|
||||
bool $nullable = true,
|
||||
$onDelete = null,
|
||||
?string $columnDefinition = null,
|
||||
?string $fieldName = null
|
||||
?string $fieldName = null,
|
||||
array $options = []
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->referencedColumnName = $referencedColumnName;
|
||||
@@ -51,5 +58,6 @@ final class InverseJoinColumn implements Annotation
|
||||
$this->onDelete = $onDelete;
|
||||
$this->columnDefinition = $columnDefinition;
|
||||
$this->fieldName = $fieldName;
|
||||
$this->options = $options;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,10 @@ final class JoinColumn implements Annotation
|
||||
*/
|
||||
public $fieldName;
|
||||
|
||||
/** @var array<string, mixed> */
|
||||
public $options = [];
|
||||
|
||||
/** @param array<string, mixed> $options */
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
string $referencedColumnName = 'id',
|
||||
@@ -47,7 +51,8 @@ final class JoinColumn implements Annotation
|
||||
bool $nullable = true,
|
||||
$onDelete = null,
|
||||
?string $columnDefinition = null,
|
||||
?string $fieldName = null
|
||||
?string $fieldName = null,
|
||||
array $options = []
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->referencedColumnName = $referencedColumnName;
|
||||
@@ -56,5 +61,6 @@ final class JoinColumn implements Annotation
|
||||
$this->onDelete = $onDelete;
|
||||
$this->columnDefinition = $columnDefinition;
|
||||
$this->fieldName = $fieldName;
|
||||
$this->options = $options;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,16 @@ final class JoinTable implements Annotation
|
||||
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */
|
||||
public $inverseJoinColumns = [];
|
||||
|
||||
/** @var array<string, mixed> */
|
||||
public $options = [];
|
||||
|
||||
/** @param array<string, mixed> $options */
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
?string $schema = null,
|
||||
$joinColumns = [],
|
||||
$inverseJoinColumns = []
|
||||
$inverseJoinColumns = [],
|
||||
array $options = []
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->schema = $schema;
|
||||
@@ -39,5 +44,6 @@ final class JoinTable implements Annotation
|
||||
$this->inverseJoinColumns = $inverseJoinColumns instanceof JoinColumn
|
||||
? [$inverseJoinColumns]
|
||||
: $inverseJoinColumns;
|
||||
$this->options = $options;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,7 @@ final class MappedSuperclass implements Annotation
|
||||
*/
|
||||
public $repositoryClass;
|
||||
|
||||
/**
|
||||
* @psalm-param class-string<EntityRepository>|null $repositoryClass
|
||||
*/
|
||||
/** @psalm-param class-string<EntityRepository>|null $repositoryClass */
|
||||
public function __construct(?string $repositoryClass = null)
|
||||
{
|
||||
$this->repositoryClass = $repositoryClass;
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use BackedEnum;
|
||||
use Doctrine\ORM\Exception\ORMException;
|
||||
use LibXMLError;
|
||||
use ReflectionException;
|
||||
use ValueError;
|
||||
|
||||
@@ -17,14 +18,14 @@ use function get_parent_class;
|
||||
use function implode;
|
||||
use function sprintf;
|
||||
|
||||
use const PHP_EOL;
|
||||
|
||||
/**
|
||||
* A MappingException indicates that something is wrong with the mapping setup.
|
||||
*/
|
||||
class MappingException extends ORMException
|
||||
{
|
||||
/**
|
||||
* @return MappingException
|
||||
*/
|
||||
/** @return MappingException */
|
||||
public static function pathRequired()
|
||||
{
|
||||
return new self('Specifying the paths to your entities is required ' .
|
||||
@@ -64,9 +65,7 @@ class MappingException extends ORMException
|
||||
return new self(sprintf("The inheritance type '%s' specified for '%s' does not exist.", $type, $entityName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MappingException
|
||||
*/
|
||||
/** @return MappingException */
|
||||
public static function generatorNotAllowedWithCompositeId()
|
||||
{
|
||||
return new self("Id generators can't be used with a composite id.");
|
||||
@@ -921,9 +920,7 @@ class MappingException extends ORMException
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
/** @return self */
|
||||
public static function invalidIndexConfiguration($className, $indexName)
|
||||
{
|
||||
return new self(
|
||||
@@ -935,9 +932,7 @@ class MappingException extends ORMException
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
/** @return self */
|
||||
public static function invalidUniqueConstraintConfiguration($className, $indexName)
|
||||
{
|
||||
return new self(
|
||||
@@ -949,9 +944,7 @@ class MappingException extends ORMException
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $givenValue
|
||||
*/
|
||||
/** @param mixed $givenValue */
|
||||
public static function invalidOverrideType(string $expectdType, $givenValue): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
@@ -1000,4 +993,19 @@ EXCEPTION
|
||||
$enumType
|
||||
), 0, $previous);
|
||||
}
|
||||
|
||||
/** @param LibXMLError[] $errors */
|
||||
public static function fromLibXmlErrors(array $errors): self
|
||||
{
|
||||
$formatter = static function (LibXMLError $error): string {
|
||||
return sprintf(
|
||||
'libxml error: %s in %s at line %d',
|
||||
$error->message,
|
||||
$error->file,
|
||||
$error->line
|
||||
);
|
||||
};
|
||||
|
||||
return new self(implode(PHP_EOL, array_map($formatter, $errors)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ interface NamingStrategy
|
||||
/**
|
||||
* Returns a table name for an entity class.
|
||||
*
|
||||
* @param string $className The fully-qualified class name.
|
||||
* @param class-string $className
|
||||
*
|
||||
* @return string A table name.
|
||||
*/
|
||||
@@ -23,8 +23,8 @@ interface NamingStrategy
|
||||
/**
|
||||
* Returns a column name for a property.
|
||||
*
|
||||
* @param string $propertyName A property name.
|
||||
* @param string|null $className The fully-qualified class name.
|
||||
* @param string $propertyName A property name.
|
||||
* @param class-string $className The fully-qualified class name.
|
||||
*
|
||||
* @return string A column name.
|
||||
*/
|
||||
@@ -33,14 +33,19 @@ interface NamingStrategy
|
||||
/**
|
||||
* Returns a column name for an embedded property.
|
||||
*
|
||||
* @param string $propertyName
|
||||
* @param string $embeddedColumnName
|
||||
* @param string $className
|
||||
* @param string $embeddedClassName
|
||||
* @param string $propertyName
|
||||
* @param string $embeddedColumnName
|
||||
* @param class-string $className
|
||||
* @param class-string $embeddedClassName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function embeddedFieldToColumnName($propertyName, $embeddedColumnName, $className = null, $embeddedClassName = null);
|
||||
public function embeddedFieldToColumnName(
|
||||
$propertyName,
|
||||
$embeddedColumnName,
|
||||
$className = null,
|
||||
$embeddedClassName = null
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the default reference column name.
|
||||
@@ -56,14 +61,14 @@ interface NamingStrategy
|
||||
*
|
||||
* @return string A join column name.
|
||||
*/
|
||||
public function joinColumnName($propertyName);
|
||||
public function joinColumnName($propertyName/*, string $className */);
|
||||
|
||||
/**
|
||||
* Returns a join table name.
|
||||
*
|
||||
* @param string $sourceEntity The source entity.
|
||||
* @param string $targetEntity The target entity.
|
||||
* @param string|null $propertyName A property name.
|
||||
* @param class-string $sourceEntity The source entity.
|
||||
* @param class-string $targetEntity The target entity.
|
||||
* @param string $propertyName A property name.
|
||||
*
|
||||
* @return string A join table name.
|
||||
*/
|
||||
@@ -72,8 +77,11 @@ interface NamingStrategy
|
||||
/**
|
||||
* Returns the foreign key column name for the given parameters.
|
||||
*
|
||||
* @param string $entityName An entity.
|
||||
* @param string|null $referencedColumnName A property.
|
||||
* @param class-string $entityName An entity.
|
||||
* @param string|null $referencedColumnName A property name or null in
|
||||
* case of a self-referencing
|
||||
* entity with join columns
|
||||
* defined in the mapping
|
||||
*
|
||||
* @return string A join column name.
|
||||
*/
|
||||
|
||||
@@ -18,9 +18,7 @@ final class OrderBy implements Annotation
|
||||
/** @var array<string> */
|
||||
public $value;
|
||||
|
||||
/**
|
||||
* @param array<string> $value
|
||||
*/
|
||||
/** @param array<string> $value */
|
||||
public function __construct(array $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
@@ -12,7 +12,6 @@ use function array_combine;
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function call_user_func_array;
|
||||
|
||||
/**
|
||||
* Utility class to retrieve all reflection instance properties of a given class, including
|
||||
@@ -45,10 +44,9 @@ final class ReflectionPropertiesGetter
|
||||
return $this->properties[$className];
|
||||
}
|
||||
|
||||
return $this->properties[$className] = call_user_func_array(
|
||||
'array_merge',
|
||||
return $this->properties[$className] = array_merge(
|
||||
// first merge because `array_merge` expects >= 1 params
|
||||
array_merge(
|
||||
...array_merge(
|
||||
[[]],
|
||||
array_map(
|
||||
[$this, 'getClassProperties'],
|
||||
|
||||
@@ -31,9 +31,7 @@ class ReflectionEmbeddedProperty extends ReflectionProperty
|
||||
/** @var Instantiator|null */
|
||||
private $instantiator;
|
||||
|
||||
/**
|
||||
* @param string $embeddedClass
|
||||
*/
|
||||
/** @param string $embeddedClass */
|
||||
public function __construct(ReflectionProperty $parentProperty, ReflectionProperty $childProperty, $embeddedClass)
|
||||
{
|
||||
$this->parentProperty = $parentProperty;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user