Compare commits

...

502 Commits
3.4.3 ... 4.0.x

Author SHA1 Message Date
Alexander M. Turek
79bff0f072 Merge branch '3.7.x' into 4.0.x
* 3.7.x:
  Make the data provider static
  Raise proper exception for invalid arguments in Base::add() (#12394)
2026-03-12 13:27:37 +01:00
Alexander M. Turek
77b579287c Merge branch '3.6.x' into 3.7.x
* 3.6.x:
  Make the data provider static
  Raise proper exception for invalid arguments in Base::add() (#12394)
2026-03-12 13:26:47 +01:00
Alexander M. Turek
27c33cf88d Merge branch '2.20.x' into 3.6.x
* 2.20.x:
  Make the data provider static
  Raise proper exception for invalid arguments in Base::add() (#12394)
2026-03-12 09:31:56 +01:00
Alexander M. Turek
6068b61a0d Make the data provider static 2026-03-12 09:24:03 +01:00
Alexander M. Turek
00024f7d88 Raise proper exception for invalid arguments in Base::add() (#12394) 2026-03-12 09:05:27 +01:00
Alexander M. Turek
44c92377a0 Merge branch '3.7.x' into 4.0.x
* 3.7.x:
  Fix code style (#12395)
  Bump actions/upload-artifact from 6 to 7 (#12387)
  Bump actions/download-artifact from 7 to 8 (#12386)
2026-03-11 16:55:56 +01:00
Alexander M. Turek
255612a1ff Merge branch '3.6.x' into 3.7.x
* 3.6.x:
  Fix code style (#12395)
  Bump actions/upload-artifact from 6 to 7 (#12387)
  Bump actions/download-artifact from 7 to 8 (#12386)
2026-03-11 16:55:34 +01:00
Alexander M. Turek
331f8b52cb Merge branch '2.20.x' into 3.6.x
* 2.20.x:
  Fix code style (#12395)
  Bump actions/upload-artifact from 6 to 7 (#12387)
  Bump actions/download-artifact from 7 to 8 (#12386)
2026-03-11 16:55:13 +01:00
Alexander M. Turek
b2faba62b7 Fix code style (#12395) 2026-03-11 16:51:15 +01:00
dependabot[bot]
da426a0036 Bump actions/upload-artifact from 6 to 7 (#12387)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-05 00:34:23 +01:00
dependabot[bot]
1891a76f13 Bump actions/download-artifact from 7 to 8 (#12386)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-05 00:33:50 +01:00
Grégoire Paris
6bb30e1cee Merge pull request #12371 from greg0ire/drop-coll-2
Drop support for Collections 2
2026-02-04 07:54:07 +01:00
Grégoire Paris
6336eb5d5d Drop support for Collections 2 2026-02-03 08:27:22 +01:00
Grégoire Paris
b8f404abcf Merge pull request #12369 from greg0ire/4.0.x
Merge 3.7.x up into 4.0.x
2026-02-03 07:58:01 +01:00
Grégoire Paris
3e8490a792 Merge remote-tracking branch 'origin/3.7.x' into 4.0.x 2026-02-02 20:34:35 +01:00
Grégoire Paris
14bb034fe4 Merge pull request #12341 from greg0ire/compat-coll3
Implement compatibility with collections 3
2026-02-02 18:29:56 +01:00
Grégoire Paris
afc0aab61a Implement compatiblity with collections 3 2026-02-01 23:19:23 +01:00
Grégoire Paris
3e784c1d9a Merge pull request #12361 from greg0ire/breaking-evmi
Leverage EventManagerInterface
2026-01-31 11:00:10 +01:00
Grégoire Paris
e1d7a13a5e Merge pull request #12368 from doctrine/3.6.x-merge-up-into-3.7.x_4EGww1uJ
Merge release 3.6.2 into 3.7.x
2026-01-30 22:55:20 +01:00
vvaswani
4262eb495b fix: update index to be serialized in __sleep() (#12366)
Signed-off-by: Vikram Vaswani <2571660+vvaswani@users.noreply.github.com`>
2026-01-30 22:41:41 +01:00
Grégoire Paris
ca49533d3e Leverage EventManagerInterface
Not having this constraint means consumers can use composition instead of
inheritance.
2026-01-30 08:34:51 +01:00
Grégoire Paris
8275471110 Merge pull request #12367 from greg0ire/4.0.x
Merge 3.7.x up into 4.0.x
2026-01-30 08:33:48 +01:00
Grégoire Paris
afd683bdb8 Merge remote-tracking branch 'origin/3.7.x' into 4.0.x 2026-01-30 07:53:25 +01:00
Grégoire Paris
fe6e5a67f8 Merge pull request #12362 from greg0ire/leverage-evm-interface
Leverage event manager interfaces
2026-01-30 07:51:38 +01:00
Grégoire Paris
b20a66dcdd Leverage event manager interfaces
Note that this involves dropping support for doctrine/event-manager 1.x,
and given that v2 only requires PHP 8.1, I think that is fine.
2026-01-29 22:37:51 +01:00
Grégoire Paris
0db02df3aa Merge pull request #12360 from doctrine/3.7.x
Merge 3.7.x up into 4.0.x
2026-01-27 21:20:51 +01:00
Grégoire Paris
dc46af27ed Merge pull request #12358 from doctrine/3.6.x
Merge 3.6.x up into 3.7.x
2026-01-26 22:40:24 +01:00
Grégoire Paris
05ab22710b Merge pull request #12349 from greg0ire/remove-has-listeners-call
Remove unnecessary check
2026-01-26 09:03:10 +01:00
Grégoire Paris
d3b47d2cbb Merge pull request #12355 from doctrine/2.20.x
Merge 2.20.x up into 3.6.x
2026-01-25 12:48:28 +01:00
Grégoire Paris
026f5bfe1b Merge pull request #12350 from greg0ire/missing-order-by
Add missing ORDER BY clause
2026-01-18 10:41:46 +01:00
Grégoire Paris
6af7de38e1 Remove unnecessary check
EventManager::dispatchEvent() already performs a similar check. So does
EventManager::getListeners()
2026-01-17 13:57:15 +01:00
Grégoire Paris
0b0f2f4d86 Add missing ORDER BY clause
This causes transient failures with PostgreSQL. Order is not guaranteed.
2026-01-17 13:39:44 +01:00
Grégoire Paris
0780b5a6b1 Merge pull request #12348 from greg0ire/4.0.x
Merge 3.7.x up into 4.0.x
2026-01-16 18:51:07 +01:00
Grégoire Paris
71b1831351 Merge remote-tracking branch 'origin/3.7.x' into 4.0.x 2026-01-16 18:30:15 +01:00
Grégoire Paris
63d9a898ec Merge pull request #12347 from doctrine/3.6.x
Merge 3.6.x up into 3.7.x
2026-01-16 18:28:50 +01:00
Grégoire Paris
0bd839a720 Merge pull request #12345 from greg0ire/3.6.x
Merge 2.20.x up into 3.6.x
2026-01-16 18:27:03 +01:00
Grégoire Paris
b65004fc26 Merge remote-tracking branch 'origin/2.20.x' into 3.6.x 2026-01-16 18:24:38 +01:00
Grégoire Paris
d2418ab074 Merge pull request #12344 from greg0ire/update-baseline
Update PHPStan baseline
2026-01-15 23:38:15 +01:00
Grégoire Paris
39a05e31c9 Update PHPStan baseline
This is caused by the release of doctrine/collections 2.7.0. The error
message is a bit shorter now.
2026-01-15 20:13:05 +01:00
Grégoire Paris
7376adede8 Merge pull request #12342 from greg0ire/override
Add Override attribute where applicable
2026-01-13 11:54:57 +01:00
sasezaki
ab156a551c Update phpstan-dbal2 to phpstan-dbal3 in .gitattributes (#12343) 2026-01-12 12:53:04 +01:00
Grégoire Paris
59f7f6793d Add Override attribute where applicable 2026-01-11 21:30:13 +01:00
Grégoire Paris
0fc9208d71 Merge pull request #12340 from greg0ire/add-missing-td
Add missing return type declaration
2026-01-10 23:18:33 +01:00
Grégoire Paris
fd9e572424 Add missing return type declaration
The class is final, so this is backward-compatible.
2026-01-10 13:01:03 +01:00
Grégoire Paris
76490f2c99 Merge pull request #12338 from doctrine/3.6.x-merge-up-into-3.7.x_8wGpvJ0m
Merge release 3.6.1 into 3.7.x
2026-01-09 10:09:17 +01:00
Grégoire Paris
2148940290 Merge pull request #12335 from greg0ire/gh-12166
Avoid lazy object initialization when initializing read-only property
2026-01-09 06:28:15 +01:00
Grégoire Paris
d3538095fd Merge pull request #12337 from greg0ire/3.6.x
Merge 2.20.x up into 3.6.x
2026-01-09 06:26:06 +01:00
Grégoire Paris
0c1bf14729 Merge remote-tracking branch 'origin/2.20.x' into 3.6.x 2026-01-08 08:55:21 +01:00
Grégoire Paris
3b8c23c51d Merge pull request #12336 from greg0ire/dmwydo
Stop mocking EventManager
2026-01-08 07:19:16 +01:00
Grégoire Paris
60d4ea694a Stop mocking EventManager
It is defined outside this repository, so let us not mock what we do not
own.
2026-01-07 21:52:47 +01:00
Grégoire Paris
e923bbc932 Avoid lazy object initialization when initializing read-only property
Initializing e.g. a readonly ID does not require loading any data from
the database. However, calling isInitialized() on the reflection of a
readonly property triggers the native lazy object initialization.
If we have a lazy property at hand, then the property cannot be initialized
already, so it is safe to skip the call.
2026-01-07 13:04:14 +01:00
n0099
8cbd34c666 Merge pull request #12060 from n0099/patch-1
Update doc `dql-custom-walkers.rst` with an output walker to interpolate parameters into SQL
2026-01-01 18:27:48 +01:00
Carlos Fernandes
f8bbdc40b0 Add dispatchPreFlushEvent() method and avoid calling getConnection() twice 2025-12-30 18:35:45 +01:00
Vladislav Sultanov
8bdefef6d1 Handle int-backed enums for values stored as string values in MySQL ENUM columns (#12275)
* FIX: Handle int-backed enums for values stored as string values in MySQL ENUM columns

Related issue: doctrine#12274

* FIX: Apply coding standard changes

Related issue: doctrine#12274

* FIX: Add unit test cases

Related issue: doctrine#12274
2025-12-30 18:21:10 +01:00
Grégoire Paris
0f8730a6e5 Merge pull request #12331 from greg0ire/a-the
Fix grammatical errors
2025-12-24 11:39:26 +01:00
Grégoire Paris
62477b5d42 Update branch metadata (#12327)
* Update branch metadata

3.6.0 has been released. As a consequence:

- 3.7.x is the next minor branch;
- 3.6.x is the current branch;
- 3.5.x is no longer maintained.

* doc: drop old releases

We should reduce the number of versions we have, so let's remove docs
for versions that have less than 2k downloads per day.
2025-12-21 00:29:57 +01:00
HypeMC
12116aa3c2 Fix docs regarding query hints (#12328) 2025-12-21 00:29:08 +01:00
Grégoire Paris
0aeddd0592 Fix grammatical errors 2025-12-20 15:34:16 +01:00
Grégoire Paris
2491c4b20d Merge pull request #12329 from HypeMC/fix-result-cache-examples
Fix result cache examples in docs
2025-12-20 09:14:39 +01:00
HypeMC
08d6167243 Fix result cache examples in docs 2025-12-20 01:21:11 +01:00
Grégoire Paris
765a9c43e6 Merge pull request #12326 from doctrine/3.6.x-merge-up-into-4.0.x_pKt05XGT
Merge release 3.6.0 into 4.0.x
2025-12-19 22:03:19 +01:00
Grégoire Paris
d4e9276e79 Merge pull request #12325 from doctrine/3.5.x
Merge 3.5.x up into 3.6.x
2025-12-19 21:36:14 +01:00
Grégoire Paris
cee74faa97 Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-12-19 20:59:05 +01:00
Grégoire Paris
9ae2181185 Merge pull request #12165 from HypeMC/debug-events-commands
Add commands for inspecting configured listeners
2025-12-19 08:31:44 +01:00
HypeMC
3e25efd72b One table 2025-12-17 23:17:36 +01:00
HypeMC
47496ed882 Fixes 2025-12-17 18:52:17 +01:00
Sadetdin EYILI
492745d710 docs: add xml example for Single Table Inheritance mapping (#12169) 2025-12-17 10:40:06 +01:00
dependabot[bot]
67419cf951 Bump actions/download-artifact from 6 to 7 (#12321) 2025-12-15 07:56:29 +01:00
dependabot[bot]
1237f5c909 Bump actions/upload-artifact from 5 to 6 (#12322) 2025-12-15 07:55:38 +01:00
Grégoire Paris
609e616f2d Merge pull request #12279 from greg0ire/deprecate-conversion
Deprecate string default expressions
2025-12-10 15:05:54 +01:00
Grégoire Paris
4016d6ba4b Deprecate string default expressions
Right now, the ORM handles the conversion of strings that happen to be
default expressions for date, time and datetime columns into the
corresponding value objects.

Let us allow users to specify these value objects directly, and
deprecate relying on the aforementioned conversion.
2025-12-10 12:08:30 +01:00
dependabot[bot]
dcdd46251e Bump doctrine/.github/.github/workflows/release-on-milestone-closed.yml (#12315)
Bumps [doctrine/.github/.github/workflows/release-on-milestone-closed.yml](https://github.com/doctrine/.github) from 13.0.0 to 13.1.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/13.0.0...13.1.0)

---
updated-dependencies:
- dependency-name: doctrine/.github/.github/workflows/release-on-milestone-closed.yml
  dependency-version: 13.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 10:23:27 +01:00
dependabot[bot]
3d98b43561 Bump doctrine/.github/.github/workflows/composer-lint.yml (#12317)
Bumps [doctrine/.github/.github/workflows/composer-lint.yml](https://github.com/doctrine/.github) from 13.0.0 to 13.1.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/13.0.0...13.1.0)

---
updated-dependencies:
- dependency-name: doctrine/.github/.github/workflows/composer-lint.yml
  dependency-version: 13.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 10:22:42 +01:00
dependabot[bot]
9f3f70944a Bump doctrine/.github/.github/workflows/coding-standards.yml (#12316)
Bumps [doctrine/.github/.github/workflows/coding-standards.yml](https://github.com/doctrine/.github) from 13.0.0 to 13.1.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/13.0.0...13.1.0)

---
updated-dependencies:
- dependency-name: doctrine/.github/.github/workflows/coding-standards.yml
  dependency-version: 13.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 10:22:15 +01:00
dependabot[bot]
05e07c0ae0 Bump doctrine/.github/.github/workflows/documentation.yml (#12318)
Bumps [doctrine/.github/.github/workflows/documentation.yml](https://github.com/doctrine/.github) from 13.0.0 to 13.1.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/13.0.0...13.1.0)

---
updated-dependencies:
- dependency-name: doctrine/.github/.github/workflows/documentation.yml
  dependency-version: 13.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 10:21:12 +01:00
Grégoire Paris
fea42ab984 Merge pull request #12299 from alexislefebvre/chore-show-parameters-in-name-of-CI-jobs
chore: show parameters in name of CI jobs
2025-11-30 11:14:14 +01:00
Alexander M. Turek
fcd9dede2e Merge branch '3.6.x' into 4.0.x
* 3.6.x:
  Remove obsolete PHPStan ignore rules
  Remove obsolete VarExporter feature detection (#12309)
  Allow Symfony 8 (#12308)
  Explicitly set a cache in testDisablingXmlValidationIsPossible (#12307)
  Removes Guides from our dependencies (#12303)
  Fix PHPStan and test errors after DBAL 4.4 and Symfony 7.4 releases (#12301)
  Support Symfony Console 8 (#12300)
  Bump doctrine/.github/.github/workflows/composer-lint.yml (#12288)
  Bump doctrine/.github/.github/workflows/documentation.yml (#12289)
  Bump doctrine/.github/.github/workflows/coding-standards.yml (#12290)
  Bump doctrine/.github/.github/workflows/release-on-milestone-closed.yml (#12291)
  Bump actions/checkout from 5 to 6 (#12292)
  Add ORDER BY clause to more test cases
  Fix check for composite foreign key
  Fix documentation about default values
  Fix eager fetch composite foreign key (#11397)
2025-11-30 01:12:51 +01:00
Alexis Lefebvre
7c347b85c1 doc: do not mention InverseJoinColumn since it’s only with PHP 8.0 (#12313) 2025-11-30 00:49:09 +01:00
Alexander M. Turek
458b040d93 Remove obsolete PHPStan ignore rules 2025-11-30 00:34:10 +01:00
Alexis Lefebvre
262c396639 doc: update minimal version of PHP (#12312) 2025-11-30 00:31:21 +01:00
Alexander M. Turek
396636a2c2 Merge branch '3.5.x' into 3.6.x
* 3.5.x:
  Remove obsolete VarExporter feature detection (#12309)
  Allow Symfony 8 (#12308)
  Explicitly set a cache in testDisablingXmlValidationIsPossible (#12307)
  Removes Guides from our dependencies (#12303)
  Fix PHPStan and test errors after DBAL 4.4 and Symfony 7.4 releases (#12301)
  Support Symfony Console 8 (#12300)
  Bump doctrine/.github/.github/workflows/composer-lint.yml (#12288)
  Bump doctrine/.github/.github/workflows/documentation.yml (#12289)
  Bump doctrine/.github/.github/workflows/coding-standards.yml (#12290)
  Bump doctrine/.github/.github/workflows/release-on-milestone-closed.yml (#12291)
  Bump actions/checkout from 5 to 6 (#12292)
2025-11-30 00:29:59 +01:00
Alexander M. Turek
78dd074266 Remove obsolete VarExporter feature detection (#12309) 2025-11-30 00:11:02 +01:00
Alexander M. Turek
ff22a00fcf Allow Symfony 8 (#12308) 2025-11-30 00:10:09 +01:00
Alexander M. Turek
02e8ff9663 Explicitly set a cache in testDisablingXmlValidationIsPossible (#12307) 2025-11-29 23:16:54 +01:00
Alexis Lefebvre
01fd55e9ea chore: show parameters in name of CI jobs 2025-11-29 23:12:27 +01:00
Alexander M. Turek
2e75a7f1c1 Merge branch '2.20.x' into 3.5.x
* 2.20.x:
  Support Symfony Console 8 (#12300)
  Bump doctrine/.github/.github/workflows/composer-lint.yml (#12288)
  Bump doctrine/.github/.github/workflows/documentation.yml (#12289)
  Bump doctrine/.github/.github/workflows/coding-standards.yml (#12290)
  Bump doctrine/.github/.github/workflows/release-on-milestone-closed.yml (#12291)
  Bump actions/checkout from 5 to 6 (#12292)
2025-11-29 22:07:13 +01:00
Alexander M. Turek
152b0e3d65 Removes Guides from our dependencies (#12303) 2025-11-29 21:55:58 +01:00
Alexander M. Turek
9d11fdd3da Fix PHPStan and test errors after DBAL 4.4 and Symfony 7.4 releases (#12301)
* Fix PHPStan errors after DBAL 4.4 and Symfony 7.4 releases

* Fix PHPStan and test errors after DBAL 4.4 and Symfony 7.4 releases
2025-11-29 18:04:54 +01:00
Alexander M. Turek
87f1ba74e0 Support Symfony Console 8 (#12300) 2025-11-29 15:03:56 +01:00
Grégoire Paris
f357a33d23 Merge pull request #12293 from doctrine/3.5.x
Merge 3.5.x. up into 3.6.x
2025-11-24 20:25:07 +01:00
Grégoire Paris
ee70178314 Merge pull request #12287 from greg0ire/more-order-by
Add ORDER BY clause to more test cases
2025-11-24 09:40:48 +01:00
dependabot[bot]
ab148d3d9d Bump doctrine/.github/.github/workflows/composer-lint.yml (#12288)
Bumps [doctrine/.github/.github/workflows/composer-lint.yml](https://github.com/doctrine/.github) from 12.2.0 to 13.0.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/v12.2.0...13.0.0)

---
updated-dependencies:
- dependency-name: doctrine/.github/.github/workflows/composer-lint.yml
  dependency-version: 13.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:25:08 +01:00
dependabot[bot]
3924c38fab Bump doctrine/.github/.github/workflows/documentation.yml (#12289)
Bumps [doctrine/.github/.github/workflows/documentation.yml](https://github.com/doctrine/.github) from 12.2.0 to 13.0.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/v12.2.0...13.0.0)

---
updated-dependencies:
- dependency-name: doctrine/.github/.github/workflows/documentation.yml
  dependency-version: 13.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:24:42 +01:00
dependabot[bot]
9814078a2c Bump doctrine/.github/.github/workflows/coding-standards.yml (#12290)
Bumps [doctrine/.github/.github/workflows/coding-standards.yml](https://github.com/doctrine/.github) from 12.2.0 to 13.0.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/v12.2.0...13.0.0)

---
updated-dependencies:
- dependency-name: doctrine/.github/.github/workflows/coding-standards.yml
  dependency-version: 13.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:24:14 +01:00
dependabot[bot]
6de5684fd9 Bump doctrine/.github/.github/workflows/release-on-milestone-closed.yml (#12291)
Bumps [doctrine/.github/.github/workflows/release-on-milestone-closed.yml](https://github.com/doctrine/.github) from 12.2.0 to 13.0.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/v12.2.0...13.0.0)

---
updated-dependencies:
- dependency-name: doctrine/.github/.github/workflows/release-on-milestone-closed.yml
  dependency-version: 13.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 09:23:46 +01:00
dependabot[bot]
c142503a52 Bump actions/checkout from 5 to 6 (#12292) 2025-11-24 07:27:27 +01:00
Grégoire Paris
01c178b297 Add ORDER BY clause to more test cases
In https://github.com/doctrine/orm/pull/12222, I thought wrongly thought
the issue I was fixing only affected one test.
2025-11-23 19:18:20 +01:00
Grégoire Paris
ffa50a777f Merge pull request #12286 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-11-21 20:24:51 +01:00
Grégoire Paris
649048f745 Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-11-21 19:46:45 +01:00
Grégoire Paris
15537bc218 Merge pull request #12285 from HypeMC/fix-is-foreign-key-composite
Fix check for composite foreign key
2025-11-21 19:29:05 +01:00
HypeMC
bc95c7c08d Fix check for composite foreign key 2025-11-21 07:27:53 +01:00
Grégoire Paris
6982c8ab9d Merge pull request #12284 from doctrine/3.5.x
Merge 3.5.x up into 3.6.x
2025-11-20 22:49:20 +01:00
Grégoire Paris
e767d2dbeb Merge pull request #12280 from greg0ire/remove-default
Remove FieldMapping::$default
2025-11-20 21:33:15 +01:00
Grégoire Paris
3df11d518c Merge pull request #12283 from doctrine/2.20.x
Merge 2.20.x up into 3.5.x
2025-11-20 21:31:19 +01:00
Grégoire Paris
c1becd54e6 Merge pull request #12281 from greg0ire/document-default-expressions
Fix documentation about default values
2025-11-20 17:58:48 +01:00
Grégoire Paris
e4d7df29c2 Fix documentation about default values
Saying it is not possible to get Doctrine to use the `DEFAULT` SQL
keyword is wrong.
2025-11-19 23:17:53 +01:00
Grégoire Paris
d65b6a6a10 Remove FieldMapping::$default
It has been deprecated in favor of $options['default'].
2025-11-19 08:08:54 +01:00
Grégoire Paris
3d8afbb7b2 Merge pull request #12278 from greg0ire/4.0.x
Merge 3.6.x up into 4.0.x
2025-11-19 08:05:56 +01:00
Grégoire Paris
736f6bc97f Merge remote-tracking branch 'origin/3.6.x' into 4.0.x 2025-11-19 07:57:42 +01:00
Grégoire Paris
608705427e Merge pull request #12277 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-11-19 07:13:23 +01:00
Grégoire Paris
f0562f4120 Merge pull request #12273 from greg0ire/deprecate-default
Deprecate FieldMapping::$default
2025-11-19 06:50:43 +01:00
Grégoire Paris
9f19310f27 Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-11-19 00:01:30 +01:00
Adrian Brajkovic
e38278bfca Fix eager fetch composite foreign key (#11397)
I think #11289 did not completely fix problem for eager fetch.
Change in that PR checked if primary key of target class is composite but that does not matter when loading collection by foreign key.
It should check if foreign key on target class is composite.

Fix from that PR did not work for me because i had entity with regular autogenerated id (single column), but foreign key referenced entity with composite primary key, like SecondLevelWithoutCompositePrimaryKey in this PR.

Checking if foreign key is composite fixed the problem for me.
2025-11-18 21:40:50 +01:00
Grégoire Paris
62f2cff218 Merge pull request #12268 from pmaasz/querybuilder-hints
Add hints to QueryBuilder
2025-11-15 09:32:24 +01:00
pmaasz
cdd774906b add member variable hints to the querybuilder for hints to be added to the query
This adds the membervariable hints to the QueryBuilder to enable setting hints
that will be applied to the query when it is created. This can help trigger
custom walker classes when the query is not adressable driectly e.g. in
Symfony Form Extensions where the quer_builder normalizer is handed the querybuilder
directly. Also see #11849
The feature mirrors the hint feature from the Query class.
This also adds tests for the hints in the QueryBuilder to ensure that those are added
correctly and applied to the query itself on creation
2025-11-14 09:11:48 +01:00
Grégoire Paris
96776e091d Deprecate FieldMapping::$default
Its purpose is unclear since there is FieldMapping::$options['default']
already.
2025-11-14 08:46:08 +01:00
Grégoire Paris
f7470d8a3f Merge pull request #12271 from greg0ire/3.6.x
Merge 3.5.x up into 3.6.x
2025-11-11 19:31:00 +01:00
Grégoire Paris
2c41cc7f1c Merge remote-tracking branch 'origin/3.5.x' into 3.6.x 2025-11-11 19:28:47 +01:00
Grégoire Paris
f18de9d569 Merge pull request #12269 from greg0ire/3.5.x
Undo merge from 3.6.x into 3.5.x
2025-11-11 19:27:40 +01:00
Grégoire Paris
37f76a8381 Undo merge from 3.6.x into 3.5.x 2025-11-11 19:11:32 +01:00
Grégoire Paris
a6c1e63a60 Merge pull request #12266 from doctrine/3.5.x-merge-up-into-3.6.x_hSSiOXm0
Merge release 3.5.6 into 3.6.x
2025-11-10 22:27:19 +01:00
Grégoire Paris
b62292256a Merge pull request #12265 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-11-10 22:11:37 +01:00
Grégoire Paris
b138395194 Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-11-10 21:32:47 +01:00
Grégoire Paris
6881cdff4c Merge pull request #12264 from doctrine/3.5.x-merge-up-into-3.6.x_9GolPzTd
Merge release 3.5.5 into 3.6.x
2025-11-10 21:27:36 +01:00
Grégoire Paris
dede2d775a Merge pull request #12262 from greg0ire/address-dbal-depr
Address default expression deprecation
2025-11-10 19:49:31 +01:00
Grégoire Paris
c502190712 Address default expression deprecation
This addresses the deprecation introduced in
https://github.com/doctrine/dbal/pull/7195

A follow-up should be to deprecate not using these value objects in
field mappings, so that we do not just reproduce the same checks that
the DBAL wants to remove.
2025-11-10 19:13:28 +01:00
Grégoire Paris
5bff0919a7 Merge pull request #12254 from elliotbruneel/fix/empty-array-query
fix: handling of empty array in SQL condition generation
2025-11-10 14:35:45 +01:00
Elliot Bruneel
9ef0f5301b fix: update SQL condition for empty array to 1=0 instead of IN (NULL) 2025-11-10 10:44:48 +01:00
Elliot Bruneel
4989ca6f15 test: add test for finding by nullable field with empty array 2025-11-05 10:03:09 +01:00
Elliot Bruneel
32d1e97ce7 chore: improve empty array check in SQL condition generation 2025-11-05 09:51:33 +01:00
Grégoire Paris
ca8147b148 Merge pull request #12257 from doctrine/dependabot/github_actions/2.20.x/doctrine/dot-github-12.2.0
Bump doctrine/.github from 12.1.0 to 12.2.0
2025-11-03 09:32:58 +01:00
dependabot[bot]
c8ebea77f0 Bump doctrine/.github from 12.1.0 to 12.2.0
Bumps [doctrine/.github](https://github.com/doctrine/.github) from 12.1.0 to 12.2.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/12.1.0...v12.2.0)

---
updated-dependencies:
- dependency-name: doctrine/.github
  dependency-version: 12.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-03 06:11:36 +00:00
Elliot Bruneel
23f22860f1 chore: update phpstan version and regenerate baseline 2025-10-31 09:04:03 +01:00
Elliot Bruneel
b24586b1b5 fix: handling of empty array in SQL condition generation 2025-10-30 17:31:04 +01:00
Grégoire Paris
0ed46303cc Merge pull request #12253 from greg0ire/4.0.x
Merge 3.6.x up into 4.0.x
2025-10-29 21:07:20 +01:00
Grégoire Paris
6e351b699c Merge remote-tracking branch 'origin/3.6.x' into 4.0.x 2025-10-29 20:51:40 +01:00
Grégoire Paris
9e5442a892 Merge pull request #12251 from doctrine/3.5.x
Merge 3.5.x up into 3.6.x
2025-10-29 20:41:29 +01:00
Grégoire Paris
7d8e51c934 Merge pull request #12250 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-10-29 08:33:35 +01:00
Grégoire Paris
2f8f1cfcb8 Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-10-29 07:31:41 +01:00
Grégoire Paris
fe5ee705db Merge pull request #12247 from greg0ire/composer-lint
Setup composer lint workflow
2025-10-29 07:28:39 +01:00
Grégoire Paris
01774c035c Merge pull request #12065 from whataboutpereira/fix-enum-discriminator-column
Use enum values from enumType in DiscriminatorColumn and check DiscriminatorMap values against it
2025-10-29 07:28:16 +01:00
Grégoire Paris
0511a9f790 Merge pull request #12248 from greg0ire/remove-mailing-list
Drop link to mailing list
2025-10-28 22:06:18 +01:00
Grégoire Paris
0e3d5e8c82 Drop link to mailing list
Who still uses this? Not me, that's for sure!
2025-10-28 21:20:15 +01:00
Grégoire Paris
72ffb3bfbf Remove archive exclude list
It is not up-to-date, and we use .gitattributes for this purpose.
2025-10-28 21:04:43 +01:00
Grégoire Paris
2e9a1adc23 Setup composer lint workflow 2025-10-28 21:03:24 +01:00
Reio Remma
6f83166266 Extract enum cases from enumType in DiscriminatorColumn
Check DiscriminatorMap keys match enum cases.
Test values are populated from enum cases and mismatched values throw an exception.
Fixes #11794
2025-10-28 20:36:11 +02:00
Grégoire Paris
ffd3f50ad7 Merge pull request #12244 from greg0ire/3.6.x
Merge 3.5.x up into 3.6.x
2025-10-27 23:46:31 +01:00
Grégoire Paris
483b45d449 Merge remote-tracking branch 'origin/3.5.x' into 3.6.x 2025-10-27 23:20:06 +01:00
Grégoire Paris
1220edf953 Merge pull request #12241 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-10-27 23:06:52 +01:00
Grégoire Paris
7e4693d629 Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-10-27 22:34:13 +01:00
Grégoire Paris
59938cae57 Merge pull request #12238 from mpdude/fix-collections-deprecation
Avoid triggering a deprecation notice in doctrine/collections
2025-10-27 22:19:59 +01:00
Grégoire Paris
298dc9bb6a Merge pull request #12183 from mpdude/paginator-confused-result-set-mapping-initialized
Paginator with output walker returns count 0 when the query has previously been executed
2025-10-27 21:54:38 +01:00
Matthias Pigulla
da67f323e0 Add PHPStan errors to persistence2 baseline file 2025-10-27 19:51:11 +01:00
Matthias Pigulla
63635cad0e Remove PHPStan error suppressions 2025-10-27 12:28:48 +01:00
Grégoire Paris
a0d401b688 Merge pull request #12239 from doctrine/dependabot/github_actions/2.20.x/actions/download-artifact-6
Bump actions/download-artifact from 5 to 6
2025-10-27 08:38:07 +01:00
Grégoire Paris
6acbadfbbe Merge pull request #12240 from doctrine/dependabot/github_actions/2.20.x/actions/upload-artifact-5
Bump actions/upload-artifact from 4 to 5
2025-10-27 08:37:52 +01:00
dependabot[bot]
c64dcb4d38 Bump actions/upload-artifact from 4 to 5
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 06:41:11 +00:00
dependabot[bot]
3304290b21 Bump actions/download-artifact from 5 to 6
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 06:22:30 +00:00
Matthias Pigulla
1865717721 Avoid triggering a deprecation notice in doctrine/collections
This updates the code to avoid triggering the deprecation introduced in https://github.com/doctrine/collections/pull/472.
2025-10-26 23:20:27 +01:00
Matthias Pigulla
828b06e20f Update the DQL walker cookbook example 2025-10-26 22:13:51 +01:00
Matthias Pigulla
c2b844d2e3 Update src/Tools/Pagination/Paginator.php
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2025-10-26 22:08:56 +01:00
Christophe Coevoet
dd4e8fe78f Merge pull request #12198 from stof/arbitrary_join_on
Update DQL arbitrary joins to use the ON keyword instead of WITH
2025-10-25 10:59:22 +02:00
Grégoire Paris
4f36f0129a Merge pull request #12236 from eltharin/bugfix_fieldalias_entityInDto
bugfix - add fieldAlias for entities in dto
2025-10-23 08:51:42 +02:00
dependabot[bot]
b45d5329f8 Bump doctrine/.github from 10.1.0 to 12.0.0 (#12227) 2025-10-23 08:10:27 +02:00
Grégoire Paris
c1047b30e3 Merge pull request #12216 from paulinevos/docs-builder
Use docs builder in ORM repo
2025-10-23 07:48:31 +02:00
eltharin
f71aa73ef1 bugfix - add fieldAlias for entities in dto 2025-10-22 21:14:42 +02:00
Grégoire Paris
aa62efa30a Adapt to latest coding standard 2025-10-22 21:12:17 +02:00
Pauline Vos
f71956f001 Use docs-builder to generate ORM docs
Introduces the `composer docs` command to generate the docs locally, and
uses the same tool (`docs-builder`) in the documentation GH workflow.
2025-10-22 21:09:03 +02:00
Alexander M. Turek
7cc210424c SQLFilter: replace internal array shape with class (#12232) 2025-10-22 09:20:35 +02:00
Grégoire Paris
4fd9e94819 Merge pull request #12234 from mpdude/merge-3.5.x-into-3.6.x
Merge 3.5.x up into 3.6.x
2025-10-22 08:31:52 +02:00
Christophe Coevoet
587caf88a7 Update DQL arbitrary joins to use the ON keyword instead of WITH
DQL arbitrary joins are semantically equivalent to SQL joins, so using
the same keyword reduces confusion. It also means that in next major
version, the WITH keyword will only be about applying adhoc filtering on
relations instead of having 2 responsibilities.
2025-10-21 17:42:48 +02:00
Matthias Pigulla
1e33b775d3 Merge remote-tracking branch 'upstream/3.5.x' into HEAD 2025-10-21 17:30:48 +02:00
Ali Sol
96f9b29573 Merge pull request #12233 from alisolphp/fix-docs-typos-2-20
Docs: fix typos and grammar across reference docs
2025-10-21 17:09:12 +02:00
Grégoire Paris
c6207b1793 Merge pull request #12202 from greg0ire/missing-suffix
Add missing "Test" suffix
2025-10-20 08:01:47 +02:00
Grégoire Paris
8c92903430 Specify the length of VARCHAR columns
Platforms in the MySQL/MariaDB family require that.
2025-10-18 14:26:12 +02:00
Grégoire Paris
8616a98023 Add missing "Test" suffix
That test never got executed.
2025-10-18 14:16:07 +02:00
Grégoire Paris
9a55cf4f30 Merge pull request #12190 from mpdude/criteria-matching-custom-type-retry
Fix collection filtering API for `IN`/`NOT IN` comparisons that require type conversions
2025-10-16 07:56:07 +02:00
Matthias Pigulla
9d680a6de4 Do not eagerly set metadata from ResolveTargetEntityListener (#12174)
* Do not eagerly set metadata from ResolveTargetEntityListener

When using the `ResolveTargetEntityListener` to substitute `targetEntities` in association mappings, do not eagerly put the resolved (target) entity into the class metadata cache under the class name of the original entity.

#### Motivation

I have a library that wants to distribute a MappedSuperclass as the base for some functionality. It will be necessary that clients using the library will extend the MappedSuperclass to fill in some blanks, creating the first real `#[Entity]` instance of it.

This client-provided entity will be the primary means of working with the class. Thus, I was following the [note in the documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/3.5/reference/inheritance-mapping.html#mapped-superclasses:~:text=It%20is%2C%20however) and using the `ResolveTargetEntityListener` to declare that whenever an association refers to that mapped superclass, the particular entity class shall be used instead.

>  One-To-Many associations are not generally possible on a mapped superclass, since they require the "many" side to hold the foreign key.
> It is, however, possible to use the [ResolveTargetEntityListener](https://www.doctrine-project.org/projects/doctrine-orm/en/3.5/cookbook/resolve-target-entity-listener.html) to replace references to a mapped superclass with an entity class at runtime. As long as there is only one entity subclass inheriting from the mapped superclass and all references to the mapped superclass are resolved to that entity class at runtime, the mapped superclass can use One-To-Many associations and be named as the targetEntity on the owning sides.

#### Changes made

The `ResolveTargetEntityListener` primarily does what its name suggests: For newly loaded class metadata, it inspects all associations declared and replaces the `targetEntity` with new (resolved) values.

But additionally, when a loaded class is the target of such a resolution, it would also put the class metadata into the cache under the name of the original entity.

I think that extra step is wrong, and this PR removes it. It had the side effect that when other classes extending the MappedSuperclass were loaded _after_ the resolve target class has been seen for the first time, the metadata for those classes would not inherit from the mapped superclass anymore, but from the target entity class instead. In my real-life use case, this causes weird mapping errors down the road; as of ^3.0, it would throw a mapping exception asking to configure inheritance mapping. But note that there would be no inheritance between the two entity classes at all.

#### More background

The documentation [describes the use of `ResolveTargetEntityListener`](https://www.doctrine-project.org/projects/doctrine-orm/en/3.5/cookbook/resolve-target-entity-listener.html) with an interface that is resolved to an entity class. For an interface, adding the extra metadata does not make a difference, since it never interferes with actual entity or mapped superclasses.

The initial idea of adding a copy of the entity class metadata under the interface name came from commit
9c7f3f2747 in #385. The goal was to make it possible to also find entities by interface names, like so:

```
$em->find('Foo\BarBundle\Entity\PersonInterface', 1);
```

It then [turned out that this only worked when the resolution had already been applied](https://github.com/doctrine/orm/pull/385#issuecomment-6658893). So, the new `onClassMetadataNotFound` event was added and the resolution map would be checked in that case as well (#1181). The inital code stayed in place, possibly giving a small performance gain.

In my real-world use case and the test case I added in this PR, the associations are even self-referencing. That should not really be necessary for the problem to surface. I decided to keep it this way to show that the `targetEntity` need not be an interface after all, and that a MappedSuperclass can be used in the same way.
2025-10-15 16:10:51 +02:00
Grégoire Paris
7602a5341c Merge pull request #12224 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-10-13 23:12:23 +02:00
Matthias Pigulla
7a59281157 Fix collection filtering API for IN/NOT IN comparisons that require type conversions
This PR fixes the `Criteria` matching API for `IN` and `NIN` conditions with values that are arrays, by making sure that type information for the matched field is passed to the DBAL level correctly.

Passing the right parameter type to DBAL is important to make sure parameter conversions are applied before matching at the database level.

Memory-based collections (`ArrayCollection`s or initialized collection fields) would perform matching on the objects in memory where no type conversion to the database representation is required, giving correct results.

But uninitialized collections that have their conditions evaluated at the database level need to convert parameter values to the database representation before performing the comparison.

One extra challenge is that the DBAL type system does currently not support array-valued parameters for custom types. Only a [limited list of types](https://www.doctrine-project.org/projects/doctrine-dbal/en/4.2/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion) is supported.

I discussed this with @morozov at the Doctrine Hackathon and came to the conclusion that it would be best to work around this limitation at the ORM level. Thus, this fix recognizes array-valued parameters and creates multiple placeholders (like `?, ?, ?`) for them, flattening out the arrays in the parameter list and repeating the type information for each one of them.

Previous stalled attempt to fix this was in #11897.
2025-10-13 23:11:56 +02:00
Grégoire Paris
214b1ad739 Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-10-13 22:53:09 +02:00
Grégoire Paris
5def068fe9 Merge pull request #12223 from doctrine/dependabot/github_actions/2.20.x/doctrine/dot-github-10.1.0
Bump doctrine/.github from 8.0.0 to 10.1.0
2025-10-13 08:49:34 +02:00
dependabot[bot]
693acbf812 Bump doctrine/.github from 8.0.0 to 10.1.0
Bumps [doctrine/.github](https://github.com/doctrine/.github) from 8.0.0 to 10.1.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/8.0.0...10.1.0)

---
updated-dependencies:
- dependency-name: doctrine/.github
  dependency-version: 10.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 06:11:35 +00:00
Grégoire Paris
28d9472a38 Merge pull request #12196 from mpdude/deprecation-notice-parser-result
Add deprecation messages for methods that were only annotated as being `@deprecated`
2025-10-12 08:32:18 +02:00
Grégoire Paris
cf11f1e453 Add ORDER BY clause to SELECT query (#12222)
The order of results is not guaranteed unless we do so, and the test can
fail in some cases:

	There was 1 failure:

	1) Doctrine\Tests\ORM\Functional\QueryTest::testToIterableWithMixedResultArbitraryJoinsScalars
	Failed asserting that two strings are equal.
	--- Expected
	+++ Actual
	@@ @@
	-'Doctrine 2'
	+'lala 2'

	/home/runner/work/orm/orm/tests/Tests/ORM/Functional/QueryTest.php:481
2025-10-12 02:02:42 +02:00
Grégoire Paris
c6955ec056 Merge pull request #12221 from greg0ire/3.6.x
Merge 3.5.x up into 3.6.x
2025-10-12 01:54:15 +02:00
Grégoire Paris
c1ce2bb687 Merge pull request #12220 from mbeccati/fix-mysql9-library
Escape library as a table name in tests (#12170)
2025-10-11 17:08:47 +02:00
Grégoire Paris
6863272943 Merge remote-tracking branch 'origin/3.5.x' into 3.6.x 2025-10-11 17:07:11 +02:00
Grégoire Paris
eae6577ce2 Merge pull request #12219 from greg0ire/rework-upgrade-md
Move introduction outside of paragraph about 3.x
2025-10-11 17:05:17 +02:00
Matteo Beccati
5f6896a2f9 Avoid using LIBRARY as table name (#12170)
It is a reserved word since MySQL 9.2:
https://dev.mysql.com/doc/refman/9.2/en/create-library.html
2025-10-11 11:56:29 +02:00
Grégoire Paris
e3106d439d Move introduction outside of paragraph about 3.x
It is not specific to 3.x and should stay forever.
2025-10-11 09:41:24 +02:00
Grégoire Paris
930a790a5a Merge pull request #12212 from mpdude/revert-11769
Revert "Fix fields of transient classes being considered duplicate with `reportFieldsWhereDeclared` (#11769)"
2025-10-10 08:17:09 +02:00
Alexander M. Turek
40aa44914f Ignore DBAL deprecation that we cannot fix (yet) (#12218) 2025-10-09 23:48:42 +02:00
Grégoire Paris
7c8a528914 Merge pull request #12211 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-10-09 22:07:50 +02:00
Christian Flothmann
3b7de17f2e add jobs using PHP 8.5 in the CI (#12180) 2025-10-09 16:39:28 +02:00
Grégoire Paris
40fedadecf Merge pull request #12217 from derrabus/bugfix/deprecated-get-name
Fix DBAL deprecation
2025-10-09 15:42:59 +02:00
Alexander M. Turek
0d97a44f28 Fix DBAL deprecation 2025-10-09 15:24:06 +02:00
Alexander M. Turek
c472a1535d Stop using deprecated Collections constants (#12214) 2025-10-09 15:02:50 +02:00
Matthias Pigulla
8afaa63d73 Add a recommendation not to use multiple private fields of the same name in entity hierarchies 2025-10-09 11:11:51 +02:00
Matthias Pigulla
2ad720b304 Revert "Fix fields of transient classes being considered duplicate with reportFieldsWhereDeclared (#11769)"
This reverts commit 4feaa470af.
2025-10-09 10:23:55 +02:00
Grégoire Paris
64cd5cad20 Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-10-09 08:05:48 +02:00
Matthias Pigulla
f1a8ee175c Add deprecation messages for two methods that were only annotated as being @deprecated 2025-10-08 23:09:14 +02:00
Alexander M. Turek
d3e1440175 Handle quoted PK columns properly on DBAL 4 (#12208) 2025-10-08 18:25:12 +02:00
Benjamin Eberlei
a9bd00a70b Improve migration docs from ORM 2 to 3. (#12207)
* Improve migration docs from ORM 2 to 3.

* Improve wording

* Hint about following deprecations.
2025-10-08 16:37:16 +02:00
Benjamin Eberlei
a939dc2e0d [GH-9219] Add support for toIterable over mixed or scalar results. (#12187)
* [GH-9219] Add support for toIterable over mixed or scalar results.

* Housekeeping: phpcs

* Update test names
2025-10-08 15:07:52 +02:00
Alexander M. Turek
758de75b45 Fix docs build 2025-10-08 11:18:04 +02:00
Alexander M. Turek
1ff63be779 Fix low-deps tests 2025-10-08 11:11:20 +02:00
Christophe Coevoet
f8186b1203 Merge pull request #12200 from mpdude/fix-invalid-dql-test-case
Fix DQL JOIN syntax in two test cases
2025-10-08 11:08:24 +02:00
Alexander M. Turek
2d5d129ee1 Merge branch '3.6.x' into 4.0.x
* 3.6.x:
  Fix missing import
  Remove calls to getMockForAbstractClass() (#12003)
  Add a CI job that fails on deprecations (#12188)
  use the empty string instead of null as an array offset (#12181)
  Upgrade to doctrine/coding-standard 14
  Bump doctrine/.github from 7.3.0 to 8.0.0
  do not call setAccessible() on PHP >= 8.1 (#12182)
  Fix docs on final entities (#12176)
  Remove Database and Model First chapters that said little of value.
  Switch to IgnoreDeprecations
  Fix php doc for getPropertyAccessors method (#12159)
  docs: consistent PostgreSQL's name case
  docs: generation strategies differences between DBAL 3 and 4
  Check extra condition to decide if a test was skipped
  Use PHPUnit 11 when possible
  Migrate away from annotations in tests
  Migrate away from assertStringNotMatchesFormat()
  Migrate to willReturn()
  Migrate away from getMockForAbstractClass()
  Fix `IN`/`NOT IN` expression handling and support enums when matching on to-many-collections
2025-10-08 10:50:52 +02:00
Alexander M. Turek
28dd32790f Merge branch '3.5.x' into 3.6.x
* 3.5.x:
  Fix missing import
  Remove calls to getMockForAbstractClass() (#12003)
  Upgrade to doctrine/coding-standard 14
  Bump doctrine/.github from 7.3.0 to 8.0.0
2025-10-08 10:32:06 +02:00
Alexander M. Turek
4f3a5c5514 Merge pull request #12201 from derrabus/bugfix/missing-import 2025-10-07 22:57:47 +02:00
Alexander M. Turek
6641989e35 Fix missing import 2025-10-07 18:02:20 +02:00
Matthias Pigulla
048e308241 Fix DQL JOIN syntax in two test cases 2025-10-07 17:54:33 +02:00
Alexander M. Turek
8ca72a4e96 Merge branch '2.20.x' into 3.5.x
* 2.20.x:
  Remove calls to getMockForAbstractClass() (#12003)
2025-10-07 17:25:14 +02:00
Alexander M. Turek
daf74b74b5 Merge commit 'c1af765960bf88cb5109f74a05d24c4df9aaf76a' into 3.5.x
* commit 'c1af765960bf88cb5109f74a05d24c4df9aaf76a':
  Upgrade to doctrine/coding-standard 14
  Bump doctrine/.github from 7.3.0 to 8.0.0
2025-10-07 16:49:06 +02:00
Alexander M. Turek
4274dac8a2 Remove calls to getMockForAbstractClass() (#12003) 2025-10-07 16:34:22 +02:00
Alexander M. Turek
ac19b21a71 Merge branch '3.5.x' into 3.6.x
* 3.5.x:
  Add a CI job that fails on deprecations (#12188)
  use the empty string instead of null as an array offset (#12181)
  do not call setAccessible() on PHP >= 8.1 (#12182)
  Fix docs on final entities (#12176)
  Remove Database and Model First chapters that said little of value.
  Switch to IgnoreDeprecations
  docs: consistent PostgreSQL's name case
  docs: generation strategies differences between DBAL 3 and 4
  Check extra condition to decide if a test was skipped
  Use PHPUnit 11 when possible
  Migrate away from annotations in tests
  Migrate away from assertStringNotMatchesFormat()
  Migrate to willReturn()
  Migrate away from getMockForAbstractClass()
  Fix `IN`/`NOT IN` expression handling and support enums when matching on to-many-collections
2025-10-07 16:07:07 +02:00
Alexander M. Turek
c6db9feade Add a CI job that fails on deprecations (#12188) 2025-10-07 16:03:42 +02:00
Grégoire Paris
c1af765960 Merge pull request #12185 from doctrine/dependabot/github_actions/2.20.x/doctrine/dot-github-8.0.0
Bump doctrine/.github from 7.3.0 to 8.0.0
2025-10-07 15:40:44 +02:00
Alexander M. Turek
86d847edb8 Merge branch '2.20.x' into 3.5.x
* 2.20.x:
  use the empty string instead of null as an array offset (#12181)
  do not call setAccessible() on PHP >= 8.1 (#12182)
2025-10-07 15:23:19 +02:00
Christian Flothmann
5f3551852f use the empty string instead of null as an array offset (#12181) 2025-10-07 14:50:23 +02:00
Grégoire Paris
8144cad07c Upgrade to doctrine/coding-standard 14 2025-10-06 09:01:36 +02:00
dependabot[bot]
70fd68cf7f Bump doctrine/.github from 7.3.0 to 8.0.0
Bumps [doctrine/.github](https://github.com/doctrine/.github) from 7.3.0 to 8.0.0.
- [Release notes](https://github.com/doctrine/.github/releases)
- [Commits](https://github.com/doctrine/.github/compare/7.3.0...8.0.0)

---
updated-dependencies:
- dependency-name: doctrine/.github
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 06:14:08 +00:00
Matthias Pigulla
437259556c Fix CS 2025-10-01 19:48:04 +02:00
Matthias Pigulla
e7e2fef56c Fix creation of the count query, to that a new RSM is being created 2025-10-01 19:46:58 +02:00
Matthias Pigulla
3e34b8e86a Add a test to reproduce the issue 2025-10-01 19:35:18 +02:00
Christian Flothmann
7d950aba62 do not call setAccessible() on PHP >= 8.1 (#12182) 2025-10-01 16:17:00 +02:00
Massimiliano Arione
8ad560c34d Fix docs on final entities (#12176) 2025-09-26 00:28:08 +02:00
Grégoire Paris
ccfb620f31 Merge pull request #12175 from beberlei/Docs-RemoveDatabaseFirstChapter
Remove Database and Model First chapters that said little of value.
2025-09-21 22:00:51 +02:00
Benjamin Eberlei
94c4d48ae5 Remove Database and Model First chapters that said little of value. 2025-09-21 21:06:16 +02:00
HypeMC
cb8a76ba3a Add commands for inspecting configured listeners 2025-09-15 15:03:52 +02:00
Grégoire Paris
2ca63df90c Merge pull request #12161 from greg0ire/proper-attribute
Switch to IgnoreDeprecations
2025-09-12 08:23:02 +02:00
Grégoire Paris
0d4413c248 Switch to IgnoreDeprecations
Rather than disabling the error handler, this attribute available since
PHPUnit 10.5 allows to be more fine-grained and ignore only the deprecations.
2025-09-10 23:58:13 +02:00
Alexander Dmitryuk
a7a14cffaf Fix php doc for getPropertyAccessors method (#12159)
Co-authored-by: a.dmitryuk <a.dmitryuk@movavi.com>
2025-09-10 02:04:32 +02:00
Grégoire Paris
cdc52b2a9e Merge pull request #12154 from greg0ire/4.0.x
Merge 3.6.x up into 4.0.x
2025-08-29 00:45:24 +02:00
Grégoire Paris
c5e2f3fb23 Merge remote-tracking branch 'origin/3.6.x' into 4.0.x 2025-08-28 08:48:00 +02:00
Grégoire Paris
48434f4c53 Merge pull request #12150 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-08-28 07:45:06 +02:00
Grégoire Paris
200a505f36 Merge pull request #12148 from lucasmirloup/docs/generation-strategies-dbal-4
docs: generation strategies: differences between DBAL 3 and 4
2025-08-27 07:42:53 +02:00
Grégoire Paris
17d7814fdc Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-08-27 00:02:52 +02:00
Grégoire Paris
8fe1200edf Merge pull request #11895 from mpdude/fix-many-to-many-in-expression
Fix `IN`/`NOT IN` expression handling and support enums when matching on to-many-collections
2025-08-26 15:32:52 +02:00
Lucas Mirloup
f7d4e379bc docs: consistent PostgreSQL's name case 2025-08-26 11:37:07 +02:00
Lucas Mirloup
c164ae434f docs: generation strategies differences between DBAL 3 and 4 2025-08-26 11:03:48 +02:00
Grégoire Paris
ceb04bf3f6 Merge pull request #12131 from rela589n/3.6.x-class-locator-doctrine-persistence-4.1
Feature: add support for `ClassLocator`
2025-08-25 23:10:55 +02:00
Grégoire Paris
21e9fcbfbb Merge pull request #12146 from greg0ire/upg-phpunit
PHPUnit 11
2025-08-24 08:30:10 +02:00
Yevhen Sidelnyk
ed9ba16ff4 Feature: add support for ClassLocator
In the scope of https://github.com/doctrine/persistence/pull/433
(available from `doctrine/persistence` >= 4.1) there was added
`ColocatedMappingDriver::$classLocator` (`ClassLocator`) property,
which allows passing any instance of `ClassLocator` for the mapping
driver to use. This commit integrates those changes into `AttributeDriver`.

Since `doctrine/orm` maintains the support for `doctrine/persistence`
of older versions, tests ensure that `ClassLocator` actually exists.

The old paths' behaviour can be adapted into the new by passing
`FileClassLocator` into `AttributeDriver`
(see `FileClassLocator::createFromDirectories($directoryPaths)`).
2025-08-23 14:26:54 +03:00
Gregoire PARIS
db456976ed Check extra condition to decide if a test was skipped
It seems that this could happen with PHPUnit 10, then tearDown() would
crash when calling `clear()` on null, but then PHPUnit 10 did not show
that exception.
2025-08-21 13:40:44 +02:00
Grégoire Paris
2d9091778f Use PHPUnit 11 when possible 2025-08-21 13:39:49 +02:00
Grégoire Paris
17059e5265 Migrate away from annotations in tests 2025-08-21 13:39:49 +02:00
Grégoire Paris
680a9ef632 Migrate away from assertStringNotMatchesFormat()
It has been deprecated.
2025-08-21 13:39:48 +02:00
Grégoire Paris
9d5f112c7e Migrate to willReturn()
self::returnValue() and self::onConsecutiveCalls() has been deprecated.
2025-08-21 13:39:48 +02:00
Grégoire Paris
b7423c96cf Migrate away from getMockForAbstractClass()
It has been deprecated.
2025-08-21 13:39:46 +02:00
Grégoire Paris
c91c3a3b1d Merge pull request #12145 from greg0ire/4.0.x
Merge 3.6.x up into 4.0.x
2025-08-19 22:32:39 +02:00
Grégoire Paris
42a693c0d3 Merge remote-tracking branch 'origin/3.6.x' into 4.0.x 2025-08-19 22:18:28 +02:00
Grégoire Paris
fc1bf3b815 Merge pull request #12144 from greg0ire/3.6.x
Merge 3.5.x up into 3.6.x
2025-08-19 22:16:20 +02:00
Grégoire Paris
b6b342cada Merge remote-tracking branch 'origin/3.5.x' into 3.6.x 2025-08-19 21:57:35 +02:00
Grégoire Paris
28735afae3 Merge pull request #12143 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-08-19 21:56:34 +02:00
Grégoire Paris
0f229fbb4b Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-08-19 21:44:21 +02:00
Alexander M. Turek
bea4814d55 Merge branch '3.5.x' into 3.6.x
* 3.5.x:
  Prefer non-deprecated AbstractAsset API (#12142)
2025-08-19 16:46:37 +02:00
Alexander M. Turek
85c13edc80 Prefer non-deprecated AbstractAsset API (#12142)
Co-authored-by: Christian Flothmann <christian.flothmann@open.de>
2025-08-19 16:46:03 +02:00
Grégoire Paris
03cc07e4d7 Merge pull request #12137 from greg0ire/forbid-nullable-on-primary-key
Forbid nullable on columns that are part of a primary key
2025-08-19 07:36:41 +02:00
Grégoire Paris
397358c308 Merge pull request #12133 from greg0ire/update-phpstan
PHPStan 2.1.22
2025-08-19 07:36:10 +02:00
Grégoire Paris
ac37a87a3d Merge pull request #12139 from doctrine/dependabot/github_actions/2.20.x/actions/checkout-5
Bump actions/checkout from 4 to 5
2025-08-18 17:31:47 +02:00
Christian Flothmann
238c15952c fix pull request URL (#12138) 2025-08-18 11:52:40 +02:00
dependabot[bot]
613f52db5a Bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 09:50:01 +00:00
Grégoire Paris
cf5503b0d8 PHPCS 3.13.2 (#12134) 2025-08-17 21:53:23 +02:00
Grégoire Paris
78fee8ea5c Forbid nullable on columns that are part of a primary key
This behavior has been deprecated.
2025-08-17 21:33:40 +02:00
Grégoire Paris
0c73cf93fa Merge pull request #12136 from doctrine/3.6.x
Merge 3.6.x up into 4.0.x
2025-08-17 21:24:30 +02:00
Grégoire Paris
fdc88ba236 Merge pull request #12135 from greg0ire/missing-assertion
Add missing assertion in test
2025-08-17 21:06:21 +02:00
Grégoire Paris
c49bf58682 Add missing assertion in test
I forgot to copy it from another test.
2025-08-17 20:51:37 +02:00
Grégoire Paris
ae5e9c8c6c PHPStan 2.1.22 2025-08-17 19:24:33 +02:00
Grégoire Paris
c03ed691d4 Merge pull request #12132 from doctrine/3.6.x
Merge 3.6.x up into 4.0.x
2025-08-17 19:10:21 +02:00
Grégoire Paris
ce844d94a0 Merge pull request #12126 from greg0ire/depr-nullable-prim-keys
Deprecate specifying nullable on primary key columns
2025-08-17 11:46:24 +02:00
Grégoire Paris
1a2826d147 Merge pull request #12053 from alexislefebvre/chore-remove-run-all.sh
chore: remove run-all.sh
2025-08-11 14:14:20 +02:00
Grégoire Paris
05760f9454 Merge pull request #12127 from doctrine/dependabot/github_actions/2.20.x/actions/download-artifact-5
Bump actions/download-artifact from 4 to 5
2025-08-11 13:06:03 +02:00
dependabot[bot]
26af013842 Bump actions/download-artifact from 4 to 5
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 10:22:17 +00:00
Max
c1f7a60c5b perf: Optimizing ScalarColumnHydrator::hydrateAllData (#12095) 2025-08-11 12:21:15 +02:00
Grégoire Paris
d1d13d5956 Deprecate specifying nullable on primary key columns
It produces no effect.
2025-08-08 22:23:32 +02:00
Grégoire Paris
4f8dde2d1e Add missing heading 2025-08-08 21:23:08 +02:00
Grégoire Paris
e3c320c705 Merge pull request #12124 from doctrine/3.5.x-merge-up-into-3.6.x_N9Rr16zf
Merge release 3.5.2 into 3.6.x
2025-08-08 19:46:47 +02:00
Grégoire Paris
5a541b8b3a Merge pull request #12121 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-08-08 19:00:40 +02:00
Grégoire Paris
9fb9cc46e4 Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-08-08 09:03:30 +02:00
Grégoire Paris
c322c71cd4 Merge pull request #12120 from greg0ire/fix-broken-comments
Fix broken comments
2025-08-08 08:55:44 +02:00
Grégoire Paris
3c733a2fee Add missing phpdoc 2025-08-08 08:34:07 +02:00
Grégoire Paris
5984ad586a Fix broken phpdoc comments 2025-08-08 08:33:39 +02:00
Grégoire Paris
ee2c3a506b Merge pull request #12097 from mvorisek/add_fixed_id_insert_count_query_test
Add 2nd level cache test for insert without post-inserted ID
2025-08-08 08:26:23 +02:00
Grégoire Paris
781ed30926 Merge pull request #12108 from greg0ire/address-deprecations
Address deprecations
2025-08-08 08:25:29 +02:00
Grégoire Paris
04694a9f7b Merge pull request #11835 from gseidel/fix-pre-persist-call-persist
fix: calling scheduleForInsert twice
2025-08-07 06:25:35 +02:00
Grégoire Paris
257c5094c4 Use not nullable columns when part of the primary key
Using a nullable column that references another table as part of a
primary key makes no sense, and is ignored by DBAL. Let us ignore it at
the ORM level.
2025-08-06 23:06:28 +02:00
Alexander M. Turek
b521e89b20 Merge branch '3.6.x' into 4.0.x
* 3.6.x:
  Don't partially mock the AbstractPlatform class (#12114)
2025-08-06 19:01:53 +02:00
Alexander M. Turek
831232e05e Merge branch '3.5.x' into 3.6.x
* 3.5.x:
  Don't partially mock the AbstractPlatform class (#12114)
2025-08-06 18:18:01 +02:00
Alexander M. Turek
66e0e92816 Don't partially mock the AbstractPlatform class (#12114) 2025-08-06 18:12:23 +02:00
Alexander M. Turek
a6a94cdefd Merge branch '3.6.x' into 4.0.x
* 3.6.x:
  Include stability in coverage file key (#12112)
  Allow Symfony 8 (#12110)
  Run tests with Symfony 8 (#12102)
  Improve comment
  Convert test into 2 unit tests
  Quote parts of the table name
2025-08-06 15:09:04 +02:00
Alexander M. Turek
a774cedb24 Include stability in coverage file key (#12112) 2025-08-06 14:03:37 +02:00
Alexander M. Turek
6b8207bb11 Allow Symfony 8 (#12110) 2025-08-06 11:05:43 +02:00
Alexander M. Turek
3d3b5b51cd Run tests with Symfony 8 (#12102) 2025-08-06 10:46:32 +02:00
Michael Voříšek
5b2060e25f Add 2nd level cache test for insert without post-inserted ID
Inserts without post-inserted ID can be sent to DB grouped together
hence the extra test.
2025-08-06 08:22:48 +02:00
Grégoire Paris
760616291b Merge pull request #12105 from doctrine/3.5.x-merge-up-into-3.6.x_OhbrLWrh
Merge release 3.5.1 into 3.6.x
2025-08-05 08:39:23 +02:00
Grégoire Paris
64444dcfd5 Merge pull request #12088 from greg0ire/quote-parts
Quote parts of the table name
2025-08-05 08:05:51 +02:00
Alexander M. Turek
c5e5742744 Merge branch '3.6.x' into 4.0.x
* 3.6.x:
  Move LazyGhost deprecation to ProxyFactory (#12101)
  Address deprecations from doctrine/dbal (#12098)
  Remove if statement
2025-08-05 00:25:15 +02:00
Alexander M. Turek
8584da8fdc Merge branch '3.5.x' into 3.6.x
* 3.5.x:
  Move LazyGhost deprecation to ProxyFactory (#12101)
  Address deprecations from doctrine/dbal (#12098)
2025-08-04 23:49:06 +02:00
Alexander M. Turek
eb2cd5375c Move LazyGhost deprecation to ProxyFactory (#12101) 2025-08-04 23:48:11 +02:00
Grégoire Paris
de7140e105 Address deprecations from doctrine/dbal (#12098)
- Non-standard flags are deprecated.
- Index::getColumns() is deprecated.
2025-08-04 23:47:55 +02:00
Grégoire Paris
07bb0def60 Merge pull request #12100 from doctrine/3.5.x
Merge 3.5.x up into 3.6.x
2025-08-04 18:11:51 +02:00
Grégoire Paris
39e35fc06c Merge pull request #12099 from alexislefebvre/2.20.x-update-supported-branches-on-README
doc: update supported branches on README (2.20.x)
2025-08-04 16:59:49 +02:00
Alexis Lefebvre
7f061c3870 doc: update supported branches on README 2025-08-04 16:38:55 +02:00
Grégoire Paris
74495711fb Merge pull request #11934 from mvorisek/fix_joined_subclass_persister_insert_of_multiple_entities
Fix JoinedSubclassPersister when multiple entities are inserted
2025-08-02 08:34:29 +02:00
Michael Voříšek
97a7cb8d2f Unify JoinedSubclassPersister dequeue
Fix JoinedSubclassPersister as BasicEntityPersister was already fixed in GH-10735.

The fix can be verified by modifying UnitOfWork to execute `BasicEntityPersister::executeInserts()` for multiple entities at once for the same entity class/persister instance - https://github.com/doctrine/orm/blob/2.20.3/src/UnitOfWork.php#L1186 - then reproducible on `Doctrine\Tests\ORM\Functional\Ticket\GH10531Test::testInserts` test.

As extending/modifying UnitOfWork in tests in not easily possible, I submit this fix for v2.x without a test.
2025-08-01 15:31:18 +02:00
Grégoire Paris
85d66de9df Improve comment
This comment is rendered useless by the phpdoc comment below it.
Instead, we can comment on what exactly "quoted" means.
2025-07-31 22:54:44 +02:00
Grégoire Paris
1b98be31ce Convert test into 2 unit tests
That test was testing too many thing and not really making it clear what
the expected output was, given some output. Instead, let us create 2
tests, each pertaining to the class under test.
2025-07-31 22:53:35 +02:00
Grégoire Paris
61f2752a80 Quote parts of the table name
In aa141bf001, I wrongly assumed that
$tableName would never contain a dot as I was not able to write a test
that caused that to happen.

The secret recipe appears to be to define a schema and to quote the
table name.

To fix it for the table name, I am calling quoteSingleIdentifier()
before doing the concatenation between schema name and table name.

To fix it for the sequence name, which seems only useful when using DBAL
3 for some reason, I reuse some of the logic of the deprecated method.

Fixes #12041
2025-07-31 21:49:43 +02:00
Grégoire Paris
f3371e1773 Merge pull request #12094 from greg0ire/simplify-test
Remove if statement
2025-07-31 17:12:39 +02:00
Grégoire Paris
6476894dc4 Remove if statement
Tests should not have conditional logic, and since a41c6d3, the else
branch of this conditional statement is dead.
2025-07-31 09:01:52 +02:00
Grégoire Paris
8b3a6dfbbb Merge pull request #12089 from doctrine/drop-useless-bool
Drop useless parameter
2025-07-30 17:17:08 +02:00
Gregoire PARIS
5634c3ccee Drop useless parameter
It was here to improve DX on 3.x
2025-07-30 16:56:05 +02:00
Grégoire Paris
a93d7d22d8 Merge pull request #12092 from greg0ire/4.0.x
Merge 3.6.x up into 4.0.x
2025-07-30 16:55:10 +02:00
Gregoire PARIS
677e0a4ed3 Merge remote-tracking branch 'origin/3.6.x' into 4.0.x 2025-07-30 16:40:28 +02:00
Grégoire Paris
8cf161d8bc Merge pull request #12091 from doctrine/3.5.x
Merge 3.5.x up into 3.6.x
2025-07-30 16:30:50 +02:00
Grégoire Paris
e0052390e1 Merge pull request #12087 from mvorisek/improve_basic_entity_persister
Improve BasicEntityPersister to be more flexible and cleaner
2025-07-30 09:44:24 +02:00
Michael Voříšek
8c6419e0e0 Prefer strict empty-array comparison over empty() call 2025-07-29 15:15:31 +02:00
Michael Voříšek
6f5ce1aca2 BasicEntityPersister: refactor $values variable into $placeholders
The new variable name is much more clearer.
2025-07-29 15:15:31 +02:00
Michael Voříšek
98e7a53b42 Remove BasicEntityPersister::$insertSql cache property
When the persister is extended to do a multi update, the caching is not
wanted. The impact is minimal as the CPU/time overhead per query is
much bigger and the prepared statement is not cached anyway.
2025-07-29 15:15:31 +02:00
Gerhard Seidel
3aaaf37dfb fix: PrePersistEventTest typos and unnecessary comments 2025-07-29 14:40:20 +02:00
Grégoire Paris
154a4652ee Merge pull request #12086 from mvorisek/add_cache_rw_strict_locking_test
Add functional strict-locking 2nd level cache test
2025-07-29 11:48:25 +02:00
Michael Voříšek
ae7489ff19 Add functional strict-locking 2nd level cache test 2025-07-28 12:14:50 +02:00
Grégoire Paris
0f32569a7a Merge pull request #12083 from greg0ire/depr-reflFields
Deprecate ClassMetadata::$reflFields
2025-07-27 23:19:29 +02:00
Gregoire PARIS
d99f74c704 Deprecate ClassMetadata::$reflFields
It is replaced with property accessors since
https://github.com/doctrine/orm/pull/11659
2025-07-24 09:55:19 +02:00
Grégoire Paris
a2990e1a0a Merge pull request #12071 from stlgaits/mapping-command-json-output
Add JSON format option for orm:mapping:describe command output
2025-07-23 07:31:41 +02:00
Grégoire Paris
d355c4a990 Merge pull request #12081 from doctrine/3.5.x
Merge 3.5.x up into 3.6.x
2025-07-22 09:58:24 +02:00
stlgaits
88c395c488 Add --em option help description for orm:mapping:describe 2025-07-22 09:45:20 +02:00
stlgaits
256d6cb0d7 Add JSON format option for orm:mapping:describe command output 2025-07-22 09:43:50 +02:00
Grégoire Paris
62ca8424d8 Merge pull request #12080 from greg0ire/3.5.x
Merge 2.20.x up into 3.5.x
2025-07-22 09:35:03 +02:00
Gregoire PARIS
3f2209a571 Merge remote-tracking branch 'origin/2.20.x' into 3.5.x 2025-07-22 09:09:21 +02:00
Grégoire Paris
1ee01f4473 Merge pull request #12078 from stlgaits/2.20.x
Fix embedded classes display in orm:mapping:command output
2025-07-22 08:48:52 +02:00
stlgaits
8a9ed138a8 Fix embedded classes display in orm:mapping:command output 2025-07-21 15:44:46 +02:00
Grégoire Paris
e714b1a2fc Merge pull request #12075 from andrew-demb/patch-1
📖 Actualize code block to be compatible with DBAL v4, use modern PHP
2025-07-15 18:16:50 +02:00
Benjamin Morel
ec0bf05853 Use PHP attributes syntax in schema validator message (#12074) 2025-07-15 00:24:16 +02:00
Andrii Dembitskyi
dc58aa3ea1 📖 Actualize code block to be compatible with DBAL v4, use modern PHP 2025-07-14 20:15:18 +03:00
Grégoire Paris
23b74e4f8b Merge pull request #12063 from wmouwen/test/gh-10788
Proxy class with BackedEnum as primary key does not convert the enum
2025-07-14 10:04:21 +02:00
Willem Mouwen
d2b699e6f5 fix: Convert BackedEnum to scalar value when binding a parameter 2025-07-12 20:50:25 +02:00
Willem Mouwen
0338d69324 test: Store an entity with a proxy association that has a BackedEnum primary identifier 2025-07-12 20:50:19 +02:00
Grégoire Paris
a1fdc6eb6e Merge pull request #12073 from doctrine/3.5.x
Merge 3.5.x up into 3.6.x
2025-07-12 10:04:59 +02:00
Grégoire Paris
d583460d63 Merge pull request #12068 from janedbal/prevent-delete-limit-misuse
QueryBuilder: prevent misuse of DELETE with LIMIT
2025-07-12 09:49:12 +02:00
Grégoire Paris
2c01dac173 Merge pull request #12072 from greg0ire/update-baseline
Update baseline because of doctrine/dbal 4.3.0
2025-07-12 09:46:50 +02:00
Grégoire Paris
137ecb491a Update baseline because of doctrine/dbal 4.3.0
This should fix the build. Maybe some of the reported issues can be
addressed, but if that is the case, it should probably be done on the
next minor branch.
2025-07-11 18:42:54 +02:00
Jan Nedbal
79d4cfdce8 Prevent misuse of DELETE with LIMIT in QueryBuilder
This fixes a dangerous bug where LIMIT is silently ignored in DELETE
      operations, potentially causing developers to delete all rows instead
      of just the intended subset. The setMaxResults() method would be
      silently omitted from the final query, making operations like
      delete last entry accidentally delete entire tables.
2025-07-10 17:31:03 +02:00
Grégoire Paris
f38ee09082 Merge pull request #12062 from janedbal/binary-id-eager-fetch-reupload
Fix unhandled ParameterType case for binary PKs
2025-07-10 17:05:57 +02:00
Jan Nedbal
6ab858a5c5 Apply suggestion from @greg0ire
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2025-07-10 16:54:02 +02:00
Jan Nedbal
3dca27ce0d Fix unhandled ParameterType case for binary PKs
Add proper handling for binary primary key parameter types that were
  previously causing runtime exceptions. The existing parameter type
  switch statement was missing a case for binary types, leading to
  unhandled scenarios when working with binary primary keys.

  This ensures consistent parameter type handling across all supported
  primary key data types in the ORM.
2025-07-07 12:07:52 +02:00
Grégoire Paris
224ff9710d Merge pull request #12050 from greg0ire/no-legacy-refl-fields
Remove ClassMetadata::$reflFields
2025-07-04 07:51:21 +02:00
Grégoire Paris
e19704e1f8 Merge pull request #12056 from greg0ire/switch-to-tags
Remove branchName from unmaintained branch
2025-07-04 07:50:39 +02:00
Alexis Lefebvre
41ea59ac66 chore: use a shorter name for CI on GitHub Actions (#12055) 2025-07-04 00:19:01 +02:00
Alexis Lefebvre
e605e6d569 doc: add links to GitHub Actions on README (#12054) 2025-07-04 00:13:51 +02:00
Grégoire Paris
9437675d3b Remove branchName from unmaintained branch
Since https://github.com/doctrine/doctrine-website/pull/372, they are no
longer necessary, it's possible to rely on tags. Once this is merged,
the branches can be removed.
2025-07-02 23:32:01 +02:00
Grégoire Paris
5301b99533 Merge pull request #12051 from greg0ire/stop-using-depr-method
Stop using QueryBuilder::getRootAlias()
2025-07-02 08:35:19 +02:00
Grégoire Paris
63409d638c Merge pull request #12048 from greg0ire/update-branch-metadata
Update branch metadata for 3.5.0
2025-07-02 08:12:04 +02:00
Alexis Lefebvre
d68c1dcd6d chore: remove run-all.sh 2025-07-02 00:14:28 +02:00
Grégoire Paris
00c7b70211 Stop using QueryBuilder::getRootAlias()
That method has been deprecated for almost 15 years, in
85d40847ac.
On top of that I'm adding a deprecation for something related that was
scheduled for deprecation at in the same commit.
2025-07-01 21:21:04 +02:00
Grégoire Paris
68c71521e7 Remove ClassMetadata::$reflFields
It has been deprecated in favor of property accessors.
2025-07-01 20:36:27 +02:00
Grégoire Paris
a2ea72c763 Merge pull request #12049 from greg0ire/4.0.x
Merge 3.5.x up into 4.0.x
2025-07-01 20:06:20 +02:00
Grégoire Paris
1492b01093 Merge remote-tracking branch 'origin/3.5.x' into 4.0.x 2025-07-01 19:53:49 +02:00
Grégoire Paris
9b9160b206 Update branch metadata for 3.5.0
3.5.0 has been released.

- 3.6.x is the new upcoming branch;
- 3.5.x is now the current branch;
- 3.4.x is no longer maintained.
2025-07-01 19:45:42 +02:00
Grégoire Paris
6deec3655b Merge pull request #12046 from greg0ire/3.5.x
Merge 3.4.x up into 3.5.x
2025-07-01 19:40:53 +02:00
Grégoire Paris
7f40422d21 Merge remote-tracking branch 'origin/3.4.x' into 3.5.x 2025-07-01 19:13:12 +02:00
Grégoire Paris
e67fa5388b Merge pull request #12043 from beberlei/Bugfix-DisableNativeLazyLogicException
Only throw PHP 8.4 requirement exception when enabling native lazy objects.
2025-06-30 23:43:15 +02:00
Grégoire Paris
80053336c9 Merge pull request #12044 from doctrine/3.4.x
Merge branch 3.4.x into 3.5.x
2025-06-30 21:53:04 +02:00
Grégoire Paris
dddcc507ef Merge pull request #12039 from xabbuh/pr-12036
do not register the legacy proxy class name resolver with enabled native lazy ghost
2025-06-30 20:38:34 +02:00
Christian Flothmann
b41d9da88d do not register the legacy proxy class name resolver with enabled native lazy ghost 2025-06-30 19:14:11 +02:00
Benjamin Eberlei
c04bfb78b7 Only throw PHP 8.4 requirement exception when enabling native lazy objects. 2025-06-30 19:01:49 +02:00
Grégoire Paris
8a5dfc86d4 Merge pull request #12037 from stlgaits/mapping-describe-completion
Add console completion for entityName param of orm:mapping:describe c…
2025-06-29 18:26:55 +02:00
Grégoire Paris
79e103c07e Merge pull request #11978 from Ocramius/feature/#11977-batch-handling-of-inserts-with-given-ids
#11977 implemented batching of `INSERT` operations in `UnitOfWork#executeInserts()` so that `EntityPersister#executeInserts()` calls are reduced
2025-06-28 22:19:54 +02:00
Grégoire Paris
68b797161e Merge pull request #12029 from greg0ire/remove-userland-proxies
Remove the possibility to use userland proxies
2025-06-28 15:26:06 +02:00
Grégoire Paris
e17b31ee68 Remove the possibility to use userland proxies
Since we bumped the minimum requirement to PHP 8.4, there no longer is a
reason to support userland proxies when we have native lazy objects at our
disposal.
2025-06-28 11:34:39 +02:00
stlgaits
5afadf163a Add console completion for entityName param of orm:mapping:describe command 2025-06-28 11:27:52 +02:00
Grégoire Paris
ac87e6e7dc Merge pull request #12038 from doctrine/3.5.x
Merge 3.5.x up into 4.0.x
2025-06-28 11:22:57 +02:00
Grégoire Paris
edfaa37228 Merge pull request #12036 from greg0ire/depr-proxy-autoload
Deprecate proxy autoloader and class name resolver
2025-06-28 11:09:37 +02:00
Grégoire Paris
ea056e98ba Deprecate proxy autoloader and class name resolver
These are only needed when not using native lazy objects.
2025-06-27 19:24:23 +02:00
Grégoire Paris
016d9d2074 Merge pull request #12035 from doctrine/3.5.x
Merge 3.5.x up into 4.0.x
2025-06-27 18:46:41 +02:00
Grégoire Paris
bab5771e98 Merge pull request #12034 from doctrine/3.4.x
Merge 3.4.x up into 3.5.x
2025-06-27 18:32:26 +02:00
Grégoire Paris
ee919d6231 Merge pull request #12030 from greg0ire/test-w-lazy-o
Rework tests and benchmarks to work with lazy objects
2025-06-27 18:13:24 +02:00
Grégoire Paris
04c390693a Merge pull request #12033 from greg0ire/remove-assert
Remove wrong assertion
2025-06-27 15:55:40 +02:00
Grégoire Paris
49293c4d48 Merge pull request #12032 from doctrine/3.4.x-merge-up-into-3.5.x_dG7qI4BR
Merge release 3.4.3 into 3.5.x
2025-06-27 14:44:44 +02:00
Gregoire PARIS
8d9e2e7d4e Remove wrong assertion
When using native lazy objects, it is plain wrong.
2025-06-27 14:42:37 +02:00
Gregoire PARIS
ed543a205c Rework tests and benchmarks to work with lazy objects
These tests and benchmarks are still relevant with lazy objects.
I am not setting up an extra job to test phpbench without native lazy
objects. Instead, I'm bumping the PHP version to 8.4 so that native lazy
objects are in use.
2025-06-27 14:12:58 +02:00
Grégoire Paris
a96697e436 Merge pull request #12028 from doctrine/3.5.x
Merge 3.5.x up into 4.0.x
2025-06-27 08:43:31 +02:00
Grégoire Paris
60ff966d54 Merge pull request #12022 from greg0ire/depr-proxy-dir
Provide upgrade path to new ORMSetup::create* signature
2025-06-27 08:12:42 +02:00
Grégoire Paris
b1ec1da8e6 Merge pull request #12027 from greg0ire/4.0.x
Merge 3.4.x up into 4.0.x
2025-06-26 21:25:54 +02:00
Grégoire Paris
6cfe0883f0 Merge remote-tracking branch 'origin/3.5.x' into 4.0.x 2025-06-26 21:12:00 +02:00
Grégoire Paris
33684253c3 Merge pull request #12026 from doctrine/3.4.x-merge-up-into-3.5.x_yt3lc4tn
Merge release 3.4.2 into 3.5.x
2025-06-26 21:07:39 +02:00
Grégoire Paris
76852cfef3 Provide upgrade path to new ORMSetup::create* signature
Currently we have ORMSetup::create*Configuration methods with a
$proxyDir argument that is used to configure the proxy directory, but
also as a seed for generating a namespace for cache systems.

Since these methods could be used with named arguments, renaming the
argument is not really an option and we need separate methods.
2025-06-26 00:14:59 +02:00
Grégoire Paris
3bd89caf36 use lowercase for word in upgrade guide 2025-06-25 23:27:18 +02:00
Grégoire Paris
eb2e7d959c Merge pull request #12020 from greg0ire/depr-legacy-proxy
Deprecate more proxies-related methods or calls
2025-06-25 23:17:56 +02:00
Grégoire Paris
a4b20356f4 Merge pull request #11988 from jannes-io/3.4.x
Add index mapping to column
2025-06-25 11:17:22 +02:00
Grégoire Paris
2550b2d1de Deprecate more proxies-related methods or calls 2025-06-25 00:04:27 +02:00
jannes
e94e1ab126 Add index mapping to Column
Adds a new option to Column mapping to add indexes to class fields
directly instead of having to use the Index() class attribute.
This allows users to define indexes in traits
where access to the class isn't available.
Fixes #11982
2025-06-24 19:50:47 +02:00
Grégoire Paris
cd56fe54bb Merge pull request #12016 from greg0ire/4.0.x
Merge 3.5.x up into 4.0.x
2025-06-24 08:15:07 +02:00
Grégoire Paris
982ef7ac56 Merge remote-tracking branch 'origin/3.5.x' into 4.0.x 2025-06-22 23:55:47 +02:00
Grégoire Paris
19e1a64a91 Merge pull request #12014 from greg0ire/3.5.x
Merge 3.4.1 up into 3.5.x
2025-06-21 13:57:03 +02:00
Grégoire Paris
082e776e91 Merge remote-tracking branch 'origin/3.4.x' into 3.5.x 2025-06-21 13:14:14 +02:00
Grégoire Paris
bbde41f712 Merge pull request #12005 from greg0ire/depr-no-lazy-objects
Deprecate not using native lazy objects on PHP 8.4+
2025-06-18 07:24:56 +02:00
Alexander M. Turek
8c0994f35f Detect DBAL's number type (#11781) 2025-06-18 02:43:47 +02:00
Grégoire Paris
3d390bc053 Deprecate not using native lazy objects on PHP 8.4+ 2025-06-18 00:14:15 +02:00
Grégoire Paris
16f1be7f10 Merge pull request #12004 from doctrine/3.4.x
Merge 3.4.x up into 3.5.x
2025-06-18 00:12:23 +02:00
Grégoire Paris
bc904f6a0c Merge pull request #11999 from greg0ire/drop-checks
Drop checks on PHP_VERSION_ID
2025-06-17 23:08:16 +02:00
Grégoire Paris
cddf985a7d Drop checks on PHP_VERSION_ID
We are requiring PHP 8.4, so all these checks are useless now.
2025-06-17 22:41:01 +02:00
Grégoire Paris
2e9ca50007 Merge pull request #11998 from greg0ire/require-php-84
Require PHP 8.4
2025-06-17 08:21:02 +02:00
Grégoire Paris
275975a444 Require PHP 8.4
It will allow us to use only native lazy objects and drop other
implementations.

I'm switching the codebase to php 8.4 style, which results in constants
being typed.
2025-06-16 23:49:26 +02:00
Grégoire Paris
2088a469cb Merge pull request #11996 from greg0ire/remove-depr-methods
Remove deprecated configuration methods
2025-06-16 23:48:18 +02:00
Gregoire PARIS
3f13f119e2 Remove deprecated configuration methods
They are no-ops or throw exceptions.
2025-06-16 09:53:02 +02:00
Grégoire Paris
d444a79bb0 Merge pull request #11995 from greg0ire/4.0.x
Merge 3.5.x up into 4.0.x
2025-06-16 09:30:14 +02:00
Grégoire Paris
01dae555bf Merge remote-tracking branch 'origin/3.5.x' into 4.0.x 2025-06-16 09:21:03 +02:00
Grégoire Paris
d9049d8ef5 Merge pull request #11994 from greg0ire/4.0.x
Merge 3.4.x up into 4.0.x
2025-06-16 09:19:31 +02:00
Grégoire Paris
1ad46527b6 Merge remote-tracking branch 'origin/3.4.x' into 4.0.x 2025-06-16 09:06:01 +02:00
Grégoire Paris
1334162a56 Merge pull request #11989 from greg0ire/late-depr
Deprecate methods for configuring no longer configurable features
2025-06-16 08:37:59 +02:00
Grégoire Paris
68ec3ebaa3 Remove trailing whitespace 2025-06-14 18:14:58 +02:00
Grégoire Paris
4f4ed2f242 Deprecate methods for configuring no longer configurable features
In 3.0.0, it is no longer possible to disable lazy ghost objects, and
likewise, it is no longer possible to disable rejecting id collisions in
the identity map, so let us deprecate the related methods.
I was supposed to do this in 3.1.0.
2025-06-14 18:14:54 +02:00
Grégoire Paris
a4b794db4f Merge pull request #11986 from doctrine/3.4.x-merge-up-into-4.0.x_b6XaoLOe
Merge release 3.4.0 into 4.0.x
2025-06-14 14:09:44 +02:00
Marco Pivetta
79cc70a62f #11977 expanded test coverage to check interleaved assigned-id vs generated-id entities
As noted by @bendavies

Ref: https://github.com/doctrine/orm/pull/11978#discussion_r2141143273
2025-06-11 23:44:24 +02:00
Marco Pivetta
4e6b5a1b0b #11977 provided method documentation / example, as per @greg0ire's feedback
Ref: https://github.com/doctrine/orm/pull/11978#discussion_r2140881217
2025-06-11 22:53:22 +02:00
Marco Pivetta
21b144fff9 #11977 removed unused type-hint, which can be completely inferred by the parameters 2025-06-11 22:50:15 +02:00
Marco Pivetta
658940de38 #11977 only perform batching if/when the AssignedGenerator is in use
The `SequenceGenerator` is potentially used for PostgreSQL table auto-generated fields, but
the `SequenceGenerator` is not a **POST**-insert generator.

Because the `SequenceGenerator` is used in the middle of `INSERT` operations performed
by persisters, we cannot rely on it in batching operations: disabling it, so we get a green
test suite on PostgreSQL.

This change makes `GH10531Test` pass on PostgreSQL: see #10531
2025-06-11 18:26:20 +02:00
Marco Pivetta
ad487370f5 #11977 hardened InsertBatchTest to check entity types of sequential batches 2025-06-11 18:16:45 +02:00
Marco Pivetta
259f83b549 #11977 added test coverage verifying that persisters are being used to batch INSERTs 2025-06-11 17:36:24 +02:00
Marco Pivetta
4a24860dcf #11977 isolated INSERT batch generation to own @internal performance-sensitive class 2025-06-11 17:18:23 +02:00
Marco Pivetta
116cdf8661 #11977 implemented simplistic (and ugly) batch handing of INSERT operations in UnitOfWork#executeInserts()
This logic also brings a minor benefit in reducing the number of times `ListenersInvoker#getSubscribedSystems`
is queried.

TODOs:

* [ ] integration test this - it is expected to reduce the number of `EntityPersister#executeInserts()` calls
* [ ] refactor this by creating a new `@internal` class for the batch, and perhaps batch via a generator
* [ ] reduce amount of repeated `getClassMetadata()` calls
* [ ] reduce overall size of `UnitOfWork` code, instead of increasing it
2025-06-11 15:43:04 +02:00
Grégoire Paris
7eeea7d66c Merge pull request #11967 from eltharin/add_arg_on_function
remove func_get_args for have "normals" arguments in function
2025-06-09 08:03:22 +02:00
Grégoire Paris
f96e812438 remove trailing whitespace 2025-06-08 11:21:45 +02:00
eltharin
d1b4aa013a remove func_get_args for have "normals" arguments in function
BC break for next major version
2025-06-08 11:21:40 +02:00
Grégoire Paris
dda313871d Merge pull request #11974 from doctrine/3.4.x
Merge 3.4.x up into 4.0.x
2025-06-07 21:17:45 +02:00
Grégoire Paris
f7584df83c Merge pull request #11972 from doctrine/3.4.x
Merge 3.4.x up into 4.0.x
2025-06-06 13:29:22 +02:00
Grégoire Paris
28b2591694 Merge pull request #11947 from doctrine/3.4.x
Merge 3.4.x up into 4.0.x
2025-05-25 18:52:09 +02:00
Grégoire Paris
528b8837e1 Merge pull request #11929 from doctrine/2.20.x-merge-up-into-2.21.x_KkdqS0u7
Merge release 2.20.3 into 2.21.x
2025-05-02 21:57:23 +02:00
Grégoire Paris
615566507c Merge pull request #11928 from greg0ire/4.0.x
Merge 3.4.x up into 4.0.x
2025-05-02 21:12:06 +02:00
Grégoire Paris
9b1cb60cbc Merge remote-tracking branch 'origin/3.4.x' into 4.0.x 2025-05-02 21:02:18 +02:00
Matthias Pigulla
9bf407f336 Fix IN/NOT IN expression handling and support enums when matching on to-many-collections
This fixes that using a `Criteria` with an `IN` or `NIN` expression on a to-many collection currently leads to an SQL error (#6173). The `ManyToMany` persister needs to know about the slightly different SQL syntax for `[NOT] IN ()`.

In the case of `[NOT] IN` expressions, the value will be an array, which also required me to change (I guess "fix") the parameter type handling. I have pulled the necessary code from the `BasicEntityPersister` and placed it as static helper methods in `PersisterHelper`.

This is somewhat inspired by #11516, which aims at fixing #11481: By re-using the parameter type handling code, it also fixes using backed enums in `EQ`, `IN` and `NIN` expressions within `Criteria` when `matching()` on one-to-many and many-to-many collections.
2025-03-30 22:44:12 +02:00
Gerhard Seidel
4fb044d5f6 fix: cs 2025-02-20 10:01:35 +08:00
Grégoire Paris
1d0e365401 Merge pull request #11841 from greg0ire/4.0.x
Merge 3.4.x up into 4.0.x
2025-02-18 23:33:10 +01:00
Grégoire Paris
c12daf5206 Merge remote-tracking branch 'origin/3.4.x' into 4.0.x 2025-02-18 23:14:53 +01:00
Gerhard Seidel
2a953c5e2b fix: PrePersistEventTest and cs 2025-02-17 14:01:08 +08:00
Gerhard Seidel
abc6a40ccb fix: calling scheduleForInsert twice
If scheduleForInsert was called in prePersist hook already, then persistNew need to check this case first, otherwise a ORMInvalidArgumentException will be thrown
2025-02-14 12:45:13 +08:00
Grégoire Paris
73e68f3c7d Merge pull request #11821 from doctrine/2.20.x-merge-up-into-2.21.x_8O8nHxqC
Merge release 2.20.2 into 2.21.x
2025-02-04 20:24:01 +01:00
Alexander M. Turek
73777d0bd4 Merge branch '2.20.x' into 2.21.x
* 2.20.x:
  Introduce testNotListedValueInEnumArray
  Fix documentation for JoinColumn nullable (#11798)
  Ignore deprecations from doctrine/common
  Fix fields of transient classes being considered duplicate with `reportFieldsWhereDeclared`
2025-01-26 19:56:20 +01:00
Grégoire Paris
e89b58a13f Merge pull request #11771 from doctrine/2.20.x-merge-up-into-2.21.x_3Yg2ZYgM
Merge release 2.20.1 into 2.21.x
2024-12-19 08:16:04 +01:00
Grégoire Paris
2b94ec18b9 Merge pull request #11759 from doctrine/2.20.x
Merge 2.20.x up into 2.21.x
2024-12-08 14:33:31 +01:00
Grégoire Paris
f7030d1844 Merge pull request #11762 from greg0ire/4.0.x
Merge 3.4.x up into 4.0.x
2024-12-08 14:05:23 +01:00
Grégoire Paris
8d7b4d8d17 Merge remote-tracking branch 'origin/3.4.x' into 4.0.x 2024-12-08 13:48:20 +01:00
Grégoire Paris
f53d35b74a Merge pull request #11730 from greg0ire/output-walker
Remove legacy implementation of the DQL -> SQL transformation
2024-12-08 11:08:01 +01:00
Grégoire Paris
2a662149f4 Merge pull request #11754 from doctrine/2.20.x
Merge 2.20.x up into 2.21.x
2024-12-07 15:39:29 +01:00
Grégoire Paris
350597beb0 Drop support for Persistence 3 (#11729) 2024-11-24 17:24:03 +01:00
Grégoire Paris
8dc17b2851 Remove legacy implementation of the DQL -> SQL transformation 2024-11-24 15:57:52 +01:00
Grégoire Paris
ee9dd474de Merge pull request #11728 from greg0ire/4.0.x
Merge 3.4.x up into 4.0.x
2024-11-23 23:36:08 +01:00
Grégoire Paris
0a4a11b6e4 Merge remote-tracking branch 'origin/3.4.x' into 4.0.x 2024-11-23 22:38:29 +01:00
Grégoire Paris
a7406cc26d Merge remote-tracking branch 'origin/3.4.x' into 4.0.x 2024-11-23 20:54:35 +01:00
Grégoire Paris
f11adcb622 Merge pull request #11689 from doctrine/3.4.x
Merge 3.4.x up into 4.0.x
2024-10-17 07:41:50 +02:00
Alexander M. Turek
1e4b88d456 Merge branch '3.4.x' into 4.0.x
* 3.4.x:
  Tell dependabot to target 2.20.x (#11681)
  Remove annotations example
  Bump doctrine/.github from 5.1.0 to 5.2.0 (#11680)
  Psalm 5.26.1 (#11677)
  CI: Close stale pull requests
  Update README (#11673)
  Fix PHPUnit deprecations
  Bump doctrine/.github from 5.1.0 to 5.2.0 (#11671)
  Experiment with literalinclude
2024-10-14 09:53:03 +02:00
Alexander M. Turek
eb5dd3f34f Remove more DBAL 3 compat code (#11675) 2024-10-13 21:19:45 +02:00
Alexander M. Turek
25066f801c Merge branch '3.3.x' into 4.0.x
* 3.3.x:
  Drop DBAL 2 compat code (#11674)
  Update branch metadata (#11672)
2024-10-13 20:56:35 +02:00
Alexander M. Turek
a0f5b4c9a3 Drop support for DBAL 4.1 (#11670) 2024-10-13 00:07:30 +02:00
Grégoire Paris
8b5148a7a8 Merge remote-tracking branch 'origin/3.3.x' into 4.0.x 2024-10-12 22:40:54 +02:00
Alexander M. Turek
22198f7c19 Merge branch '3.3.x' into 4.0.x
* 3.3.x:
  Remove vendor prefix of PHPDoc referencing class-string (#11643)
  Deprecate the `\Doctrine\ORM\Query\Parser::setCustomOutputTreeWalker()` method (#11641)
2024-10-09 22:54:08 +02:00
Alexander M. Turek
9cf5593759 Merge branch '3.3.x' into 4.0.x
* 3.3.x:
  Stop recommending vendor-prefixed PHPDoc (#11640)
  Let PHPStan detect deprecated usages (#11639)
  PHPStan 1.12.6 (#11635)
  Add upgrade note about property hooks (#11636)
  Prepare PHP 8.4 support: Prevent property hooks from being used (#11628)
  Use E_ALL instead of E_ALL | E_STRICT
  Add CI job for PHP 8.4
  fix generating duplicate method stubs
2024-10-09 21:54:51 +02:00
Grégoire Paris
b5c0e0154f Remove int from union type
This case is no longer necessary now that we have a ParameterType enum.
2024-10-09 10:29:38 +02:00
Grégoire Paris
dbf26dbf90 Merge remote-tracking branch 'origin/3.3.x' into 4.0.x 2024-10-09 10:14:02 +02:00
Grégoire Paris
9b09cd03c0 Merge pull request #11519 from greg0ire/remove-db-driver
Remove DatabaseDriver
2024-06-22 15:46:04 +02:00
Grégoire Paris
2c489fb8b3 Remove DatabaseDriver 2024-06-22 11:39:08 +02:00
Alexander M. Turek
42a36e19a5 Merge branch '3.3.x' into 4.0.x
* 3.3.x:
  Fix deprecated array access usage (#11517)
  Address doctrine/persistence 3.3.3 release
  Add the propoer void return type on the __load method of proxies
  Deprecate DatabaseDriver
  Remove unneeded CS rule
  Fix OneToManyPersister::deleteEntityCollection missing discriminator column/value. (GH-11500)
  Skip joined entity creation for empty relation (#10889)
  ci: maintained and stable mariadb version (11.4 current lts) (#11490)
  fix(docs): use string value in `addAttribute`
  Replace assertion with exception (#11489)
  Use ramsey/composer-install in PHPBench workflow
  update EntityManager#transactional to EntityManager#wrapInTransaction
  Fix cloning entities
  Consider usage of setFetchMode when checking for simultaneous usage of fetch-mode EAGER and WITH condition.
  Update branch metadata (#11474)
2024-06-21 14:01:17 +02:00
Grégoire Paris
f46d8a1742 Merge pull request #11510 from greg0ire/missing-type-hint
Add missing type declaration
2024-06-20 14:35:40 +02:00
Grégoire Paris
1eb67b7ca1 Add missing type declaration 2024-06-19 22:02:03 +02:00
Grégoire Paris
00b29a13f2 Merge pull request #11473 from doctrine/3.2.x-merge-up-into-4.0.x_1iG5LEAr
Merge release 3.2.0 into 4.0.x
2024-05-23 16:42:47 +02:00
Alexander M. Turek
a22e0fda8e Remove NotSupported (#11471) 2024-05-23 07:16:41 +02:00
Alexander M. Turek
b58946a11f Merge branch '3.2.x' into 4.0.x
* 3.2.x:
  Deprecate the NotSupported exception (#11470)
2024-05-22 21:54:30 +02:00
Alexander M. Turek
d973867dc0 Drop support for DBAL 3 (#11216) 2024-05-22 14:10:25 +02:00
Alexander M. Turek
ac5a17da2e Remove Serializable implementation (#11469) 2024-05-22 11:50:28 +02:00
Alexander M. Turek
f4bbf8e1d0 Merge branch '3.2.x' into 4.0.x
* 3.2.x:
  Deprecate SequenceGenerator implementing Serializable (#11468)
2024-05-22 10:51:35 +02:00
Alexander M. Turek
95a0000446 Merge branch '3.2.x' into 4.0.x
* 3.2.x:
  Psalm 5.24.0 (#11467)
  PHPStan 1.11.1 (#11466)
2024-05-21 14:25:44 +02:00
Alexander M. Turek
b2a09b9c4e Merge branch '3.2.x' into 4.0.x
* 3.2.x:
  Fix failed merge (#11464)
  Test with actual lock modes (#11465)
  Backport test for Query::setLockMode() (#11463)
  Fix return type of Query::getLockMode() (#11462)
2024-05-21 14:05:02 +02:00
Alexander M. Turek
3695d5793d Merge branch '3.2.x' into 4.0.x
* 3.2.x:
  Using an integer as discriminator value with ORM v3
  Using an integer as discriminator value with ORM v3
  Bump ramsey/composer-install from 2 to 3 (#11442)
  Use ramsey/composer-install in PHPBench workflow (#11444)
  Bump doctrine/.github from 3.0.0 to 5.0.1
  Upgrade codecov/codecov-action
  Setup Dependabot
  Make test compatible with PHP 7.1
  Fix deprecation layer
  Remove unused test group
  Keep entities in identity map until the scheduled deletions are executed.
  Update association-mapping.rst
  fix: always cleanup in `AbstractHydrator::toIterable()` (#11101)
  Respect orderBy for EAGER fetch mode
  fix(docs): typo
2024-05-21 08:43:08 +02:00
Alexander M. Turek
9674168572 Merge branch '3.2.x' into 4.0.x
* 3.2.x:
  Revert "Merge pull request #11399 from ThomasLandauer/issue-11377" (#11415)
  Fix BIGINT validation (#11414)
  docs: update PHP version in doc
  Fix fromMappingArray definition
  Fix templated phpdoc return type (#11407)
  [Documentation] Merging "Query Result Formats" with "Hydration Modes"
  SchemaValidator: Changing mapping of BIGINT to string|int
  Fix psalm errors: remove override of template type
  Update dql-doctrine-query-language.rst
  Adding `NonUniqueResultException`
  [Documentation] Query Result Formats
2024-04-15 16:31:30 +02:00
Alexander M. Turek
80aec02fd7 Merge branch '3.2.x' into 4.0.x
* 3.2.x:
  Adjust PHPBench mocks
  Set column length explicitly (#11393)
  Add missing import
  Remove unused variable (#11391)
  Fixed proxy initialization for EnumReflectionProperty
  Remove older versions from the docs (#11383)
  [Documentation] Removing "Doctrine Mapping Types" ... (#11384)
  [GH-11185] Bugfix: do not use collection batch loading for indexBy assocations. (#11380)
  Improve lazy ghost performance by avoiding self-referencing closure. (#11376)
  Remove outdated git metadata files (#11362)
  Switch join columns around, otherwise index doesnt match
  Key on fk
  Fix entities and mapping.
  Minor code style fix in AbstractRemoteControl
  Do not schedule batch loading for target classes with composite identifier.
  Cleanup tests not to use model sets.
  provides a test case for github issue 11154
2024-03-21 15:16:26 +01:00
Grégoire Paris
637cd6e405 Merge pull request #11353 from DaDeather/11351-remove-obsolete-indexes-and-unique-constraint-properties-from-table-attribute
Remove obsolete and unnecessary properties from `Table` attribute (#11351)
2024-03-18 09:12:14 +01:00
Ismail Özgün Turan
9430d56d78 Remove obsolete and unnecessary properties from Table attribute (#11351)
The properties `indexes` and `uniqueConstraints` were present before and
were used for the `AnnotationDriver` but were never implemented
for the `AttributeDriver`.
Since the `AnnotationDriver` doesn't exist anymore these can be safely
removed reducing possible confusion when defining indices and
uniqueConstraints in the `Table` attribute which never worked anyway.
2024-03-18 08:31:32 +01:00
Grégoire Paris
a4e71b8df7 Merge pull request #11367 from doctrine/3.2.x
Merge 3.2.x up into 4.0.x
2024-03-18 08:13:06 +01:00
Grégoire Paris
f20955901a Merge pull request #11356 from greg0ire/remove--complete
Remove --complete option of orm:schema-tool:update
2024-03-18 08:12:47 +01:00
Grégoire Paris
54c36d2a55 Remove --complete option of orm:schema-tool:update
That option achieved nothing anymore.
2024-03-15 08:47:52 +01:00
Grégoire Paris
ea7cc64911 Merge pull request #11355 from greg0ire/4.0.x
Merge 3.2.x up into 4.0.x
2024-03-15 08:45:32 +01:00
Grégoire Paris
22947da46b Merge remote-tracking branch 'origin/3.2.x' into 4.0.x 2024-03-15 08:35:33 +01:00
Alexander M. Turek
2928b9331a Remove ReflectionEnumProperty (#11334) 2024-03-03 22:13:36 +01:00
Alexander M. Turek
fdd84a2290 Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  Prepare releases 2.19 and 3.1 (#11335)
2024-03-03 18:46:03 +01:00
Alexander M. Turek
8c1ad6f0c5 Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  Fix annotation
  Bump CI workflows (#11336)
  Fix SchemaTool::getSchemaFromMetadata() uniqueConstraint without a predefined name (#11314)
2024-03-03 18:04:09 +01:00
Alexander M. Turek
a5cb7c26c5 Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  Use class from persistence package  (#11330)
  Refator array_map into simple loop for performance. (#11332)
2024-03-03 14:33:43 +01:00
Alexander M. Turek
f8b5ef03d5 Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  Psalm 5.22.2 (#11326)
2024-03-01 11:01:25 +01:00
Alexander M. Turek
e80f03c5d8 Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  Bump Doctrine Collections to 2.2 (#11325)
  Use enum_exists() for enums
  Remove PHP 7 workarounds (#11324)
2024-03-01 09:28:26 +01:00
Alexander M. Turek
c1d61802cd Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  PHPStan 1.10.59 (#11320)
  Address deprecations from Collection 2.2 (#11315)
  Deprecate invalid method call
  Throw a full-fledged exception on invalid call
  Remove extra word
  Fix sql walker phpdoc
2024-03-01 08:23:55 +01:00
Grégoire Paris
ca8631c172 Merge pull request #11306 from greg0ire/cleanup-deprecations
Disallow passing null to ClassMetadata::fullyQualifiedClassName()
2024-02-28 20:43:58 +01:00
Grégoire Paris
518d16b9cb Disallow passing null to ClassMetadata::fullyQualifiedClassName() 2024-02-25 11:11:52 +01:00
Grégoire Paris
7679fc0f4f Merge pull request #11304 from doctrine/3.1.x
Merge 3.1.x up into 4.0.x
2024-02-25 10:56:49 +01:00
Alexander M. Turek
c5ef72d060 Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  Backport QueryParameterTest (#11288)
  Test different ways of settings query parameters
  Be less restrictive in DiscriminatorColumnMapping phpdoc (#11226)
  Allow (Array)ParameterType in QueryBuilder
  Do not implicitly cast glob's return type
  Do not cast file_put_contents's return type
  Do not implicitly cast getLockTime()'s return type
  Do not implicitly cast getLockContent()'s return value
2024-02-22 13:53:02 +01:00
Alexander M. Turek
cbab4d6a14 Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  Fix Static Analysis folder reference (#11281)
  Remove broken assertion from DateAddFunction and DateSubFunction (#11243)
  Account for inversedBy being a non-falsy-string or null
  Improve static analysis on AttachEntityListenersListener
  docs: recommend safer way to disable logging (#11269)
  Remove unused baseline entries
  Treat '0' as a legitimate trim char
  Add type field mapper documentation to the sidebar
  Mark document as orphan
  Use correction sectionauthor syntax
  Remove unused trait
  [Documentation] Adding link to Postgres upgrade article (#11257)
  Validate more variadic parameters (#11261)
  Throw if a variadic parameter contains unexpected named arguments (#11260)
  Make docs valid according to guides 0.3.3 (#11252)
  fix: support array-type arg in QB variadic calls (#11242)
2024-02-21 22:20:20 +01:00
Alexander M. Turek
5733eced42 Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  Remove references to deprecated constants from Lexer (#11234)
2024-02-07 15:43:44 +01:00
Alexander M. Turek
0917109c50 Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  Add TokenType class (#11228)
  Revert "Merge pull request #11229 from greg0ire/add-columns"
  Add columns for 3.1.x and 4.0x
  Update version ORM from 2 to 3 in docs (#11221)
  Clean up outdated sentence (#11224)
  Update README.md
  Point link to correct upgrade guide (#11220)
  Ignore subclasses without discriminatorValue when generating discriminator column condition SQL (#11200)
  Update branches in README
2024-02-07 14:21:45 +01:00
Alexander M. Turek
615eb926f4 Merge branch '3.1.x' into 4.0.x
* 3.1.x:
  Bump dependencies in the "getting started" docs page (#11219)
  DoctrineSetup was renamed to ORMSetup (#11218)
2024-02-04 17:45:54 +01:00
Grégoire Paris
d734ab38fa Merge pull request #11215 from greg0ire/remove-array-access
Remove array access
2024-02-04 13:52:52 +01:00
Grégoire Paris
0446f5b4b5 Remove array access 2024-02-04 11:27:46 +01:00
503 changed files with 7740 additions and 6421 deletions

View File

@@ -12,41 +12,17 @@
"upcoming": true
},
{
"name": "3.5",
"branchName": "3.5.x",
"slug": "3.5",
"name": "3.7",
"branchName": "3.7.x",
"slug": "3.7",
"upcoming": true
},
{
"name": "3.4",
"branchName": "3.4.x",
"slug": "3.4",
"name": "3.6",
"branchName": "3.6.x",
"slug": "3.6",
"current": true
},
{
"name": "3.3",
"branchName": "3.3.x",
"slug": "3.3",
"maintained": false
},
{
"name": "3.2",
"branchName": "3.2.x",
"slug": "3.2",
"maintained": false
},
{
"name": "3.1",
"branchName": "3.1.x",
"slug": "3.1",
"maintained": false
},
{
"name": "3.0",
"branchName": "3.0.x",
"slug": "3.0",
"maintained": false
},
{
"name": "2.21",
"branchName": "2.21.x",
@@ -61,63 +37,33 @@
},
{
"name": "2.19",
"branchName": "2.19.x",
"slug": "2.19",
"maintained": false
},
{
"name": "2.18",
"branchName": "2.18.x",
"slug": "2.18",
"maintained": false
},
{
"name": "2.17",
"branchName": "2.17.x",
"slug": "2.17",
"maintained": false
},
{
"name": "2.16",
"branchName": "2.16.x",
"slug": "2.16",
"maintained": false
},
{
"name": "2.15",
"branchName": "2.15.x",
"slug": "2.15",
"maintained": false
},
{
"name": "2.14",
"branchName": "2.14.x",
"slug": "2.14",
"maintained": false
},
{
"name": "2.13",
"branchName": "2.13.x",
"slug": "2.13",
"maintained": false
},
{
"name": "2.12",
"branchName": "2.12.x",
"slug": "2.12",
"maintained": false
},
{
"name": "2.11",
"branchName": "2.11.x",
"slug": "2.11",
"maintained": false
},
{
"name": "2.10",
"branchName": "2.10.x",
"slug": "2.10",
"maintained": false
}
]
}

3
.gitattributes vendored
View File

@@ -11,11 +11,10 @@ build.properties.dev export-ignore
build.xml export-ignore
CONTRIBUTING.md export-ignore
phpunit.xml.dist export-ignore
run-all.sh export-ignore
phpcs.xml.dist export-ignore
phpbench.json export-ignore
phpstan.neon export-ignore
phpstan-baseline.neon export-ignore
phpstan-dbal2.neon export-ignore
phpstan-dbal3.neon export-ignore
phpstan-params.neon export-ignore
phpstan-persistence2.neon export-ignore

View File

@@ -24,4 +24,4 @@ on:
jobs:
coding-standards:
uses: "doctrine/.github/.github/workflows/coding-standards.yml@7.3.0"
uses: "doctrine/.github/.github/workflows/coding-standards.yml@13.1.0"

20
.github/workflows/composer-lint.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: "Composer Lint"
on:
pull_request:
branches:
- "*.x"
paths:
- ".github/workflows/composer-lint.yml"
- "composer.json"
push:
branches:
- "*.x"
paths:
- ".github/workflows/composer-lint.yml"
- "composer.json"
jobs:
composer-lint:
name: "Composer Lint"
uses: "doctrine/.github/.github/workflows/composer-lint.yml@13.1.0"

View File

@@ -1,4 +1,4 @@
name: "Continuous Integration"
name: "CI: PHPUnit"
on:
pull_request:
@@ -25,49 +25,58 @@ env:
jobs:
phpunit-smoke-check:
name: "PHPUnit with SQLite"
name: >
SQLite -
${{ format('PHP {0} - DBAL {1} - ext. {2} - proxy {3}',
matrix.php-version || 'Ø',
matrix.dbal-version || 'Ø',
matrix.extension || 'Ø',
matrix.proxy || 'Ø'
) }}
runs-on: "ubuntu-22.04"
strategy:
matrix:
php-version:
- "8.1"
- "8.2"
- "8.3"
- "8.4"
- "8.5"
dbal-version:
- "default"
- "3.7"
extension:
- "sqlite3"
- "pdo_sqlite"
deps:
- "highest"
native_lazy:
- "0"
stability:
- "stable"
include:
- php-version: "8.2"
- php-version: "8.4"
dbal-version: "4@dev"
extension: "pdo_sqlite"
native_lazy: "0"
- php-version: "8.2"
stability: "stable"
- php-version: "8.4"
dbal-version: "4@dev"
extension: "sqlite3"
native_lazy: "0"
- php-version: "8.1"
stability: "stable"
- php-version: "8.4"
dbal-version: "default"
deps: "lowest"
extension: "pdo_sqlite"
native_lazy: "0"
stability: "stable"
- php-version: "8.4"
dbal-version: "default"
deps: "highest"
extension: "pdo_sqlite"
native_lazy: "1"
stability: "stable"
- php-version: "8.4"
dbal-version: "default"
deps: "highest"
extension: "sqlite3"
stability: "dev"
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v6"
with:
fetch-depth: 2
@@ -79,6 +88,14 @@ jobs:
coverage: "pcov"
ini-values: "zend.assertions=1, apc.enable_cli=1"
- name: "Allow dev dependencies"
run: |
composer config minimum-stability dev
composer remove --no-update --dev phpbench/phpbench phpdocumentor/guides-cli
composer require --no-update symfony/console:^8 symfony/var-exporter:^8 doctrine/dbal:^4.4
composer require --dev --no-update symfony/cache:^8
if: "${{ matrix.stability == 'dev' }}"
- name: "Require specific DBAL version"
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
if: "${{ matrix.dbal-version != 'default' }}"
@@ -93,48 +110,100 @@ jobs:
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage-no-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 0
ENABLE_NATIVE_LAZY_OBJECTS: ${{ matrix.native_lazy }}
- name: "Run PHPUnit with Second Level Cache"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --exclude-group performance,non-cacheable,locking_functional --coverage-clover=coverage-cache.xml"
- name: "Run PHPUnit with Second Level Cache and PHPUnit 10"
run: |
vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml \
--exclude-group=performance,non-cacheable,locking_functional \
--coverage-clover=coverage-cache.xml
if: "${{ matrix.php-version == '8.1' }}"
env:
ENABLE_SECOND_LEVEL_CACHE: 1
ENABLE_NATIVE_LAZY_OBJECTS: ${{ matrix.native_lazy }}
- name: "Run PHPUnit with Second Level Cache and PHPUnit 11+"
run: |
vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml \
--exclude-group=performance \
--exclude-group=non-cacheable \
--exclude-group=locking_functional \
--coverage-clover=coverage-cache.xml
if: "${{ matrix.php-version != '8.1' }}"
env:
ENABLE_SECOND_LEVEL_CACHE: 1
- name: "Upload coverage file"
uses: "actions/upload-artifact@v4"
uses: "actions/upload-artifact@v7"
with:
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.deps }}-${{ matrix.native_lazy }}-coverage"
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.deps }}-${{ matrix.stability }}-coverage"
path: "coverage*.xml"
phpunit-deprecations:
name: "PHPUnit (fail on deprecations)"
runs-on: "ubuntu-24.04"
steps:
- name: "Checkout"
uses: "actions/checkout@v5"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "8.5"
extensions: "apcu, pdo, sqlite3"
coverage: "pcov"
ini-values: "zend.assertions=1, apc.enable_cli=1"
- name: "Allow dev dependencies"
run: composer config minimum-stability dev
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v3"
with:
composer-options: "--ignore-platform-req=php+"
dependency-versions: "highest"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite3.xml --fail-on-deprecation"
env:
ENABLE_SECOND_LEVEL_CACHE: 0
ENABLE_NATIVE_LAZY_OBJECTS: 1
phpunit-postgres:
name: "PHPUnit with PostgreSQL"
name: >
${{ format('PostgreSQL {0} - PHP {1} - DBAL {2} - ext. {3}',
matrix.postgres-version || 'Ø',
matrix.php-version || 'Ø',
matrix.dbal-version || 'Ø',
matrix.extension || 'Ø'
) }}
runs-on: "ubuntu-22.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "8.2"
- "8.3"
- "8.4"
- "8.5"
dbal-version:
- "default"
- "3.7"
postgres-version:
- "17"
extension:
- pdo_pgsql
- pgsql
include:
- php-version: "8.2"
- php-version: "8.4"
dbal-version: "4@dev"
postgres-version: "14"
extension: pdo_pgsql
- php-version: "8.2"
dbal-version: "3.7"
postgres-version: "9.6"
- php-version: "8.4"
dbal-version: "default"
postgres-version: "10"
extension: pdo_pgsql
services:
@@ -151,7 +220,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v6"
with:
fetch-depth: 2
@@ -176,26 +245,30 @@ jobs:
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v4"
uses: "actions/upload-artifact@v7"
with:
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.extension }}-coverage"
path: "coverage.xml"
phpunit-mariadb:
name: "PHPUnit with MariaDB"
name: >
${{ format('MariaDB {0} - PHP {1} - DBAL {2} - ext. {3}',
matrix.mariadb-version || 'Ø',
matrix.php-version || 'Ø',
matrix.dbal-version || 'Ø',
matrix.extension || 'Ø'
) }}
runs-on: "ubuntu-22.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "8.2"
- "8.3"
- "8.4"
- "8.5"
dbal-version:
- "default"
- "3.7"
- "4@dev"
mariadb-version:
- "11.4"
@@ -218,7 +291,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v6"
with:
fetch-depth: 2
@@ -243,26 +316,30 @@ jobs:
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v4"
uses: "actions/upload-artifact@v7"
with:
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
path: "coverage.xml"
phpunit-mysql:
name: "PHPUnit with MySQL"
name: >
${{ format('MySQL {0} - PHP {1} - DBAL {2} - ext. {3}',
matrix.mysql-version || 'Ø',
matrix.php-version || 'Ø',
matrix.dbal-version || 'Ø',
matrix.extension || 'Ø'
) }}
runs-on: "ubuntu-22.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "8.2"
- "8.3"
- "8.4"
- "8.5"
dbal-version:
- "default"
- "3.7"
mysql-version:
- "5.7"
- "8.0"
@@ -270,11 +347,11 @@ jobs:
- "mysqli"
- "pdo_mysql"
include:
- php-version: "8.2"
- php-version: "8.4"
dbal-version: "4@dev"
mysql-version: "8.0"
extension: "mysqli"
- php-version: "8.2"
- php-version: "8.4"
dbal-version: "4@dev"
mysql-version: "8.0"
extension: "pdo_mysql"
@@ -293,7 +370,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v6"
with:
fetch-depth: 2
@@ -319,13 +396,27 @@ jobs:
env:
ENABLE_SECOND_LEVEL_CACHE: 0
- name: "Run PHPUnit with Second Level Cache"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --exclude-group performance,non-cacheable,locking_functional --coverage-clover=coverage-no-cache.xml"
- name: "Run PHPUnit with Second Level Cache and PHPUnit 10"
run: |
vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml \
--exclude-group=performance,non-cacheable,locking_functional \
--coverage-clover=coverage-no-cache.xml"
if: "${{ matrix.php-version == '8.1' }}"
env:
ENABLE_SECOND_LEVEL_CACHE: 1
- name: "Run PHPUnit with Second Level Cache and PHPUnit 11+"
run: |
vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml \
--exclude-group=performance \
--exclude-group=non-cacheable \
--exclude-group=locking_functional \
--coverage-clover=coverage-no-cache.xml
if: "${{ matrix.php-version != '8.1' }}"
env:
ENABLE_SECOND_LEVEL_CACHE: 1
- name: "Upload coverage files"
uses: "actions/upload-artifact@v4"
uses: "actions/upload-artifact@v7"
with:
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
path: "coverage*.xml"
@@ -343,12 +434,12 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v6"
with:
fetch-depth: 2
- name: "Download coverage files"
uses: "actions/download-artifact@v4"
uses: "actions/download-artifact@v8"
with:
path: "reports"

View File

@@ -17,4 +17,4 @@ on:
jobs:
documentation:
name: "Documentation"
uses: "doctrine/.github/.github/workflows/documentation.yml@7.3.0"
uses: "doctrine/.github/.github/workflows/documentation.yml@13.1.0"

View File

@@ -32,11 +32,11 @@ jobs:
strategy:
matrix:
php-version:
- "8.1"
- "8.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v6"
with:
fetch-depth: 2

View File

@@ -7,7 +7,7 @@ on:
jobs:
release:
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@7.3.0"
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@13.1.0"
secrets:
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}

View File

@@ -25,17 +25,9 @@ jobs:
name: Static Analysis with PHPStan
runs-on: ubuntu-22.04
strategy:
matrix:
include:
- dbal-version: default
config: phpstan.neon
- dbal-version: 3.8.2
config: phpstan-dbal3.neon
steps:
- name: "Checkout code"
uses: "actions/checkout@v4"
uses: "actions/checkout@v6"
- name: Install PHP
uses: shivammathur/setup-php@v2
@@ -44,13 +36,8 @@ jobs:
php-version: "8.4"
tools: cs2pr
- name: Require specific DBAL version
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
if: "${{ matrix.dbal-version != 'default' }}"
- name: Install dependencies with Composer
uses: ramsey/composer-install@v2
- name: Run static analysis with phpstan/phpstan
run: "vendor/bin/phpstan analyse -c ${{ matrix.config }} --error-format=checkstyle | cs2pr"
run: "vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr"

View File

@@ -1,9 +1,9 @@
| [4.0.x][4.0] | [3.5.x][3.5] | [3.4.x][3.4] | [2.21.x][2.21] | [2.20.x][2.20] |
| [4.0.x][4.0] | [3.7.x][3.7] | [3.6.x][3.6] | [2.21.x][2.21] | [2.20.x][2.20] |
|:------------------------------------------------------:|:------------------------------------------------------:|:------------------------------------------------------:|:--------------------------------------------------------:|:--------------------------------------------------------:|
| [![Build status][4.0 image]][4.0] | [![Build status][3.5 image]][3.5] | [![Build status][3.4 image]][3.4] | [![Build status][2.21 image]][2.21] | [![Build status][2.20 image]][2.20] |
| [![Coverage Status][4.0 coverage image]][4.0 coverage] | [![Coverage Status][3.5 coverage image]][3.5 coverage] | [![Coverage Status][3.4 coverage image]][3.4 coverage] | [![Coverage Status][2.21 coverage image]][2.21 coverage] | [![Coverage Status][2.20 coverage image]][2.20 coverage] |
| [![Build status][4.0 image]][4.0 workflow] | [![Build status][3.7 image]][3.7 workflow] | [![Build status][3.6 image]][3.6 workflow] | [![Build status][2.21 image]][2.21 workflow] | [![Build status][2.20 image]][2.20 workflow] |
| [![Coverage Status][4.0 coverage image]][4.0 coverage] | [![Coverage Status][3.7 coverage image]][3.7 coverage] | [![Coverage Status][3.6 coverage image]][3.6 coverage] | [![Coverage Status][2.21 coverage image]][2.21 coverage] | [![Coverage Status][2.20 coverage image]][2.20 coverage] |
Doctrine ORM is an object-relational mapper for PHP 8.1+ that provides transparent persistence
Doctrine ORM is an object-relational mapper for PHP 8.4+ 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
@@ -18,21 +18,26 @@ without requiring unnecessary code duplication.
[4.0 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=4.0.x
[4.0]: https://github.com/doctrine/orm/tree/4.0.x
[4.0 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A4.0.x
[4.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/4.0.x/graph/badge.svg
[4.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/4.0.x
[3.5 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.5.x
[3.5]: https://github.com/doctrine/orm/tree/3.5.x
[3.5 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.5.x/graph/badge.svg
[3.5 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.5.x
[3.4 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.4.x
[3.4]: https://github.com/doctrine/orm/tree/3.4.x
[3.4 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.4.x/graph/badge.svg
[3.4 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.4.x
[3.7 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.7.x
[3.7]: https://github.com/doctrine/orm/tree/3.7.x
[3.7 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A3.7.x
[3.7 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.7.x/graph/badge.svg
[3.7 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.7.x
[3.6 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.6.x
[3.6]: https://github.com/doctrine/orm/tree/3.6.x
[3.6 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A3.6.x
[3.6 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.6.x/graph/badge.svg
[3.6 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.6.x
[2.21 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.21.x
[2.21]: https://github.com/doctrine/orm/tree/2.21.x
[2.21 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A2.21.x
[2.21 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.21.x/graph/badge.svg
[2.21 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.21.x
[2.20 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.20.x
[2.20]: https://github.com/doctrine/orm/tree/2.20.x
[2.20 workflow]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml?query=branch%3A2.20.x
[2.20 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.20.x/graph/badge.svg
[2.20 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.20.x

View File

@@ -1,3 +1,399 @@
Note about upgrading: Doctrine uses static and runtime mechanisms to raise
awareness about deprecated code.
- Use of `@deprecated` docblock that is detected by IDEs (like PHPStorm) or
Static Analysis tools (like Psalm, phpstan)
- Use of our low-overhead runtime deprecation API, details:
https://github.com/doctrine/deprecations/
# Upgrade to 4.0
## BC BREAK: EventManager to EventManagerInterface migration
The following methods used to return an instance of `Doctrine\Common\EventManager`,
and now return an instance of `Doctrine\Common\EventManagerInterface`:
- `Doctrine\ORM\EntityManager::getEventManager()`
- `Doctrine\ORM\EntityManagerDecorator::getEventManager()`
- `Doctrine\ORM\EntityManagerInterface::getEventManager()`
## BC BREAK: Remove `FieldMapping::$default`
The `default` property of `Doctrine\ORM\Mapping\FieldMapping` has been removed.
Use `FieldMapping::$options['default']` instead.
## BC BREAK: throw on `nullable` on columns that end up being used in a primary key
Specifying `nullable` on join columns that are part of a primary key is
an error and will cause an exception to be thrown.
## BC BREAK: `Doctrine\ORM\Mapping\LegacyReflectionFields` is removed
The `Doctrine\ORM\Mapping\LegacyReflectionFields` class has been removed.
Also, `Doctrine\ORM\Mapping\ClassMetadata::$reflFields` has been removed, as
well as methods depending on it.
## BC BREAK: Userland lazy objects are no longer supported
Userland lazy objects are no longer supported.
[Native lazy objects](https://www.php.net/manual/en/language.oop5.lazy-objects.php)
are used instead.
## BC BREAK: type declarations on constants
All constants in the ORM now have type declarations and are final. You may no
longer override them in extending types.
## Remove methods for configuring no longer configurable features
Since 3.0, lazy ghosts are enabled unconditionally, and so is rejecting ID
collisions in the identity map.
As a consequence, the following methods are removed:
* `Doctrine\ORM\Configuration::setLazyGhostObjectEnabled()`
* `Doctrine\ORM\Configuration::isLazyGhostObjectEnabled()`
* `Doctrine\ORM\Configuration::setRejectIdCollisionInIdentityMap()`
* `Doctrine\ORM\Configuration::isRejectIdCollisionInIdentityMapEnabled()`
## BC BREAK: New argument to `NewObjectExpression::dispatch()`
```diff
<?php
class NewObjectExpression extends Node
{
// …
- public function dispatch(SqlWalker $walker): string
+ public function dispatch(SqlWalker $walker, string|null $parentAlias = null): string
{
// …
}
}
```
## BC BREAK: New argument to `AbstractEntityPersister::buildCollectionCacheKey()`
```diff
<?php
abstract class AbstractEntityPersister implements CachedEntityPersister
{
// …
protected function buildCollectionCacheKey(
AssociationMapping $association,
array $ownerId,
+ string $filterHash
): CollectionCacheKey {
// …
}
}
```
## Require implementation of `OutputWalker`, remove `SqlWalker::getExecutor()`
The `SqlWalker::getExecutor()` method is removed. Output walkers should
implement the `\Doctrine\ORM\Query\OutputWalker` interface and create
`Doctrine\ORM\Query\Exec\SqlFinalizer` instances.
## Remove `DatabaseDriver`
The class `Doctrine\ORM\Mapping\Driver\DatabaseDriver` is removed.
## Remove the `NotSupported` exception
The class `Doctrine\ORM\Exception\NotSupported` has been removed without replacement.
## Remove remaining `Serializable` implementation
`SequenceGenerator` does not implement the `Serializable` interface anymore.
The following methods have been removed:
* `SequenceGenerator::serialize()`
* `SequenceGenerator::unserialize()`
## Remove `orm:schema-tool:update` option `--complete`
That option was a no-op.
## Remove `Doctrine\ORM\Mapping\ReflectionEnumProperty`
This class has been removed.
Instead, use `Doctrine\Persistence\Reflection\EnumReflectionProperty` from
`doctrine/persistence`.
## Forbid passing null to `ClassMetadata::fullyQualifiedClassName()`
Passing `null` to `Doctrine\ORM\ClassMetadata::fullyQualifiedClassName()` is
no longer possible.
## Remove array access
Using array access on instances of the following classes is no longer possible:
- `Doctrine\ORM\Mapping\DiscriminatorColumnMapping`
- `Doctrine\ORM\Mapping\EmbedClassMapping`
- `Doctrine\ORM\Mapping\FieldMapping`
- `Doctrine\ORM\Mapping\JoinColumnMapping`
- `Doctrine\ORM\Mapping\JoinTableMapping`
## Remove properties `$indexes` and `$uniqueConstraints` from `Doctrine\ORM\Mapping\Table`
The properties `$indexes` and `$uniqueConstraints` have been removed since they had no effect at all.
The preferred way of defining indices and unique constraints is by
using the `\Doctrine\ORM\Mapping\UniqueConstraint` and `\Doctrine\ORM\Mapping\Index` attributes.
# Upgrade to 3.x General Notes
We recommend you upgrade to DBAL 3 first before upgrading to ORM 3. See
the DBAL upgrade docs: https://github.com/doctrine/dbal/blob/3.10.x/UPGRADE.md
Rather than doing several major upgrades at once, we recommend you do the following:
- upgrade to DBAL 3
- deploy and monitor
- upgrade to ORM 3
- deploy and monitor
- upgrade to DBAL 4
- deploy and monitor
If you are using Symfony, the recommended minimal Doctrine Bundle version is 2.15
to run with ORM 3.
At this point, we recommend upgrading to PHP 8.4 first and then directly from
ORM 2.19 to 3.5 and up so that you can skip the lazy ghost proxy generation
and directly start using native lazy objects.
>>>>>>> origin/3.6.x
# Upgrade to 3.7
## Conditional breaking changes
3.7 adds support for `doctrine/collections` 3. If you upgrade to that version
of `doctrine/collections`, there are breaking changes in `doctrine/orm` as well,
because of cross-package inheritance and type declarations.
Most notably, `Doctrine\ORM\PersistentCollection::add` no longer returns a boolean:
```diff
- public function add(mixed $value): bool
+ public function add(mixed $value): void
```
That method always returned `true`, so you can safely stop using the return
value before upgrading.
Also, if you extend `Doctrine\ORM\Persisters\SqlValueVisitor`, you need to
ensure the following methods have a return type in your subclasses:
- `walkComparison()`
- `walkCompositeExpression()`
- `walkValue()`
## Deprecate `EventManager` return type in `EntityManager` methods
The return type of the following methods has been changed from
`Doctrine\Common\EventManager` to `Doctrine\Common\EventManagerInterface`:
- `Doctrine\ORM\Decorator\EntityManagerDecorator::getEventManager()`
- `Doctrine\ORM\EntityManager::getEventManager()`
- `Doctrine\ORM\EntityManagerInterface::getEventManager()`
All three methods continue to return an instance of `EventManager`, however
relying on that is deprecated and will no longer be the guaranteed in 4.0.
# Upgrade to 3.6
## Deprecate using string expression for default values in mappings
Using a string expression for default values in field mappings is deprecated.
Use `Doctrine\DBAL\Schema\DefaultExpression` instances instead.
Here is how to address this deprecation when mapping entities using PHP attributes:
```diff
use DateTime;
+use Doctrine\DBAL\Schema\DefaultExpression\CurrentDate;
+use Doctrine\DBAL\Schema\DefaultExpression\CurrentTime;
+use Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
final class TimeEntity
{
#[ORM\Id]
#[ORM\Column]
public int $id;
- #[ORM\Column(options: ['default' => 'CURRENT_TIMESTAMP'], insertable: false, updatable: false)]
+ #[ORM\Column(options: ['default' => new CurrentTimestamp()], insertable: false, updatable: false)]
public DateTime $createdAt;
- #[ORM\Column(options: ['default' => 'CURRENT_TIME'], insertable: false, updatable: false)]
+ #[ORM\Column(options: ['default' => new CurrentTime()], insertable: false, updatable: false)]
public DateTime $createdTime;
- #[ORM\Column(options: ['default' => 'CURRENT_DATE'], insertable: false, updatable: false)]
+ #[ORM\Column(options: ['default' => new CurrentDate()], insertable: false, updatable: false)]
public DateTime $createdDate;
}
```
Here is how to do the same when mapping entities using XML:
```diff
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Doctrine\Tests\ORM\Functional\XmlTimeEntity">
<id name="id" type="integer" column="id">
<generator strategy="AUTO"/>
</id>
<field name="createdAt" type="datetime" insertable="false" updatable="false">
<options>
- <option name="default">CURRENT_TIMESTAMP</option>
+ <option name="default">
+ <object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp"/>
+ </option>
</options>
</field>
<field name="createdAtImmutable" type="datetime_immutable" insertable="false" updatable="false">
<options>
- <option name="default">CURRENT_TIMESTAMP</option>
+ <option name="default">
+ <object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp"/>
+ </option>
</options>
</field>
<field name="createdTime" type="time" insertable="false" updatable="false">
<options>
- <option name="default">CURRENT_TIME</option>
+ <option name="default">
+ <object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentTime"/>
+ </option>
</options>
</field>
<field name="createdDate" type="date" insertable="false" updatable="false">
<options>
- <option name="default">CURRENT_DATE</option>
+ <option name="default">
+ <object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentDate"/>
+ </option>
</options>
</field>
</entity>
</doctrine-mapping>
```
## Deprecate `FieldMapping::$default`
The `default` property of `Doctrine\ORM\Mapping\FieldMapping` is deprecated and
will be removed in 4.0. Instead, use `FieldMapping::$options['default']`.
## Deprecate specifying `nullable` on columns that end up being used in a primary key
Specifying `nullable` on join columns that are part of a primary key is
deprecated and will be an error in 4.0.
This can happen when using a join column mapping together with an id mapping,
or when using a join column mapping or an inverse join column mapping on a
many-to-many relationship.
```diff
class User
{
#[ORM\Id]
#[ORM\Column(type: 'integer')]
private int $id;
#[ORM\Id]
#[ORM\ManyToOne(targetEntity: Family::class, inversedBy: 'users')]
- #[ORM\JoinColumn(name: 'family_id', referencedColumnName: 'id', nullable: true)]
+ #[ORM\JoinColumn(name: 'family_id', referencedColumnName: 'id')]
private ?Family $family;
#[ORM\ManyToMany(targetEntity: Group::class)]
#[ORM\JoinTable(name: 'user_group')]
- #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: true)]
- #[ORM\InverseJoinColumn(name: 'group_id', referencedColumnName: 'id', nullable: true)]
+ #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id')]
+ #[ORM\InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')]
private Collection $groups;
}
```
## Deprecate `Doctrine\ORM\QueryBuilder::add('join', ...)` with a list of join parts
Using `Doctrine\ORM\QueryBuilder::add('join', ...)` with a list of join parts
is deprecated in favor of using an associative array of join parts with the
root alias as key.
## Deprecate using the `WITH` keyword for arbitrary DQL joins
Using the `WITH` keyword to specify the condition for an arbitrary DQL join is
deprecated in favor of using the `ON` keyword (similar to the SQL syntax for
joins).
The `WITH` keyword is now meant to be used only for filtering conditions in
association joins.
# Upgrade to 3.5
See the General notes to upgrading to 3.x versions above.
## Deprecate not using native lazy objects on PHP 8.4+
Having native lazy objects disabled on PHP 8.4+ is deprecated and will not be
possible in 4.0.
You can enable them through configuration:
```php
$config->enableNativeLazyObjects(true);
```
As a consequence, methods, parameters and commands related to userland lazy
objects have been deprecated on PHP 8.4+:
- `Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand`
- `Doctrine\ORM\Configuration::getAutoGenerateProxyClasses()`
- `Doctrine\ORM\Configuration::getProxyDir()`
- `Doctrine\ORM\Configuration::getProxyNamespace()`
- `Doctrine\ORM\Configuration::setAutoGenerateProxyClasses()`
- `Doctrine\ORM\Configuration::setProxyDir()`
- `Doctrine\ORM\Configuration::setProxyNamespace()`
- Passing more than one argument to `Doctrine\ORM\Proxy\ProxyFactory::__construct()`
Additionally, some methods of ORMSetup have been deprecated in favor of a new
counterpart.
- `Doctrine\ORM\ORMSetup::createAttributeMetadataConfiguration()` is deprecated in favor of
`Doctrine\ORM\ORMSetup::createAttributeMetadataConfig()`
- `Doctrine\ORM\ORMSetup::createXMLMetadataConfiguration()` is deprecated in favor of
`Doctrine\ORM\ORMSetup::createXMLMetadataConfig()`
- `Doctrine\ORM\ORMSetup::createConfiguration()` is deprecated in favor of
`Doctrine\ORM\ORMSetup::createConfig()`
## Deprecate methods for configuring no longer configurable features
Since 3.0, lazy ghosts are enabled unconditionally, and so is rejecting ID
collisions in the identity map.
As a consequence, the following methods are deprecated and will be removed in 4.0:
* `Doctrine\ORM\Configuration::setLazyGhostObjectEnabled()`
* `Doctrine\ORM\Configuration::isLazyGhostObjectEnabled()`
* `Doctrine\ORM\Configuration::setRejectIdCollisionInIdentityMap()`
* `Doctrine\ORM\Configuration::isRejectIdCollisionInIdentityMapEnabled()`
# Upgrade to 3.4.1
## BC BREAK: You can no longer use the `.*` notation to get all fields of an entity in a DTO
@@ -7,6 +403,8 @@ decide to remove it before it is used too widely.
# Upgrade to 3.4
See the General notes to upgrading to 3.x versions above.
## Discriminator Map class duplicates
Using the same class several times in a discriminator map is deprecated.
@@ -23,8 +421,12 @@ that implements `ArrayAccess`.
Use the new `Doctrine\ORM\Mapping\PropertyAccessors\PropertyAccessor` API and access
through `Doctrine\ORM\Mapping\ClassMetadata::$propertyAccessors` instead.
Companion accessor methods are deprecated as well.
# Upgrade to 3.3
See the General notes to upgrading to 3.x versions above.
## Deprecate `DatabaseDriver`
The class `Doctrine\ORM\Mapping\Driver\DatabaseDriver` is deprecated without replacement.
@@ -41,6 +443,8 @@ method. Details can be found at https://github.com/doctrine/orm/pull/11188.
# Upgrade to 3.2
See the General notes to upgrading to 3.x versions above.
## Deprecate the `NotSupported` exception
The class `Doctrine\ORM\Exception\NotSupported` is deprecated without replacement.
@@ -67,6 +471,8 @@ using the `\Doctrine\ORM\Mapping\UniqueConstraint` and `\Doctrine\ORM\Mapping\In
# Upgrade to 3.1
See the General notes to upgrading to 3.x versions above.
## Deprecate `Doctrine\ORM\Mapping\ReflectionEnumProperty`
This class is deprecated and will be removed in 4.0.
@@ -90,6 +496,8 @@ Using array access on instances of the following classes is deprecated:
# Upgrade to 3.0
See the General notes to upgrading to 3.x versions above.
## BC BREAK: Calling `ClassMetadata::getAssociationMappedByTargetField()` with the owning side of an association now throws an exception
Previously, calling
@@ -115,6 +523,9 @@ so `$targetEntity` is a first argument now. This change affects only non-named a
When using the `AUTO` strategy to let Doctrine determine the identity generation mechanism for
an entity, and when using `doctrine/dbal` 4, PostgreSQL now uses `IDENTITY`
instead of `SEQUENCE` or `SERIAL`.
There are three ways to handle this change.
* If you want to upgrade your existing tables to identity columns, you will need to follow [migration to identity columns on PostgreSQL](https://www.doctrine-project.org/projects/doctrine-dbal/en/4.0/how-to/postgresql-identity-migration.html)
* If you want to keep using SQL sequences, you need to configure the ORM this way:
```php
@@ -127,6 +538,27 @@ $configuration->setIdentityGenerationPreferences([
PostgreSQLPlatform::CLASS => ClassMetadata::GENERATOR_TYPE_SEQUENCE,
]);
```
* You can change individual entities to use the `SEQUENCE` strategy instead of `AUTO`:
```php
diff --git a/src/Entity/Example.php b/src/Entity/Example.php
index 28be8df378..3b7d61bda6 100644
--- a/src/Entity/Example.php
+++ b/src/Entity/Example.php
@@ -38,7 +38,7 @@ class Example
#[ORM\Id]
#[ORM\Column(type: 'integer')]
- #[ORM\GeneratedValue(strategy: 'AUTO')]
+ #[ORM\GeneratedValue(strategy: 'SEQUENCE')]
private int $id;
#[Assert\Length(max: 255)]
```
The later two options require a small database migration that will remove the default
expression fetching the next value from the sequence. It's not strictly necessary to
do this migration because the code will work anyway. A benefit of this approach is
that you can just make and roll out the code changes first and then migrate the database later.
## BC BREAK: Throw exceptions when using illegal attributes on Embeddable
@@ -2046,7 +2478,7 @@ from 2.0 have to configure the annotation driver if they don't use `Configuratio
## Scalar mappings can now be omitted from DQL result
You are now allowed to mark scalar SELECT expressions as HIDDEN an they are not hydrated anymore.
You are now allowed to mark scalar SELECT expressions as HIDDEN and they are not hydrated anymore.
Example:
SELECT u, SUM(a.id) AS HIDDEN numArticles FROM User u LEFT JOIN u.Articles a ORDER BY numArticles DESC HAVING numArticles > 10

View File

@@ -1,17 +1,77 @@
{
"name": "doctrine/orm",
"type": "library",
"description": "Object-Relational-Mapper for PHP",
"keywords": ["orm", "database"],
"homepage": "https://www.doctrine-project.org/projects/orm.html",
"license": "MIT",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
{"name": "Marco Pivetta", "email": "ocramius@gmail.com"}
"type": "library",
"keywords": [
"orm",
"database"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"homepage": "https://www.doctrine-project.org/projects/orm.html",
"require": {
"php": "^8.4",
"ext-ctype": "*",
"composer-runtime-api": "^2",
"doctrine/collections": "^3",
"doctrine/dbal": "^4.2.1",
"doctrine/deprecations": "^1.1",
"doctrine/event-manager": "^2.1.1",
"doctrine/inflector": "^1.4 || ^2.0",
"doctrine/instantiator": "^1.3 || ^2",
"doctrine/lexer": "^3",
"doctrine/persistence": "^4",
"psr/cache": "^1 || ^2 || ^3",
"symfony/console": "^5.4 || ^6.0 || ^7.0 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^14.0",
"phpbench/phpbench": "^1.0",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "2.1.23",
"phpstan/phpstan-deprecation-rules": "^2",
"phpunit/phpunit": "^11.5.42",
"psr/log": "^1 || ^2 || ^3",
"symfony/cache": "^5.4 || ^6.2 || ^7.0 || ^8.0",
"symfony/var-exporter": "^6.3.9 || ^7.0 || ^8.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"
},
"autoload": {
"psr-4": {
"Doctrine\\ORM\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Doctrine\\Performance\\": "tests/Performance",
"Doctrine\\StaticAnalysis\\": "tests/StaticAnalysis",
"Doctrine\\Tests\\": "tests/Tests"
}
},
"config": {
"allow-plugins": {
"composer/package-versions-deprecated": true,
@@ -20,49 +80,7 @@
},
"sort-packages": true
},
"require": {
"php": "^8.1",
"composer-runtime-api": "^2",
"ext-ctype": "*",
"doctrine/collections": "^2.2",
"doctrine/dbal": "^3.8.2 || ^4",
"doctrine/deprecations": "^0.5.3 || ^1",
"doctrine/event-manager": "^1.2 || ^2",
"doctrine/inflector": "^1.4 || ^2.0",
"doctrine/instantiator": "^1.3 || ^2",
"doctrine/lexer": "^3",
"doctrine/persistence": "^3.3.1 || ^4",
"psr/cache": "^1 || ^2 || ^3",
"symfony/console": "^5.4 || ^6.0 || ^7.0",
"symfony/var-exporter": "^6.3.9 || ^7.0"
},
"require-dev": {
"doctrine/coding-standard": "^13.0",
"phpbench/phpbench": "^1.0",
"phpdocumentor/guides-cli": "^1.4",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "2.0.3",
"phpstan/phpstan-deprecation-rules": "^2",
"phpunit/phpunit": "^10.4.0",
"psr/log": "^1 || ^2 || ^3",
"squizlabs/php_codesniffer": "3.12.0",
"symfony/cache": "^5.4 || ^6.2 || ^7.0"
},
"suggest": {
"ext-dom": "Provides support for XSD validation for XML mapping files",
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0"
},
"autoload": {
"psr-4": { "Doctrine\\ORM\\": "src" }
},
"autoload-dev": {
"psr-4": {
"Doctrine\\Tests\\": "tests/Tests",
"Doctrine\\StaticAnalysis\\": "tests/StaticAnalysis",
"Doctrine\\Performance\\": "tests/Performance"
}
},
"archive": {
"exclude": ["!vendor", "tests", "*phpunit.xml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp"]
"scripts": {
"docs": "composer --working-dir docs update && ./docs/vendor/bin/build-docs.sh @additional_args"
}
}

2
docs/.gitignore vendored
View File

@@ -1,3 +1,3 @@
composer.lock
vendor/
build/
output/

View File

@@ -1,24 +0,0 @@
# Makefile for Doctrine ORM documentation
#
# You can set these variables from the command line.
DOCOPTS =
BUILD = vendor/bin/guides
BUILDDIR = build
# Internal variables.
ALLGUIDESOPTS = $(DOCOPTS) en/
.PHONY: help clean html
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
clean:
-rm -rf ./$(BUILDDIR)/*
html:
$(BUILD) $(ALLGUIDESOPTS) --output=$(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

View File

@@ -4,19 +4,15 @@ The documentation is written in [ReStructured Text](https://docutils.sourceforge
## How to Generate:
In the `docs/` folder, run
In the project root, run
composer update
composer docs
Then compile the documentation with:
make html
This will generate the documentation into the `build` subdirectory.
This will generate the documentation into the `docs/output` subdirectory.
To browse the documentation, you need to run a webserver:
cd build/html
cd docs/output
php -S localhost:8000
Now the documentation is available at [http://localhost:8000](http://localhost:8000).

View File

@@ -3,8 +3,7 @@
"description": "Documentation for the Object-Relational Mapper\"",
"type": "library",
"license": "MIT",
"require": {
"phpdocumentor/guides-cli": "1.7.1",
"phpdocumentor/filesystem": "1.7.1"
"require-dev": {
"doctrine/docs-builder": "^1.0"
}
}

View File

@@ -40,7 +40,8 @@ Now this is all awfully technical, so let me come to some use-cases
fast to keep you motivated. Using walker implementation you can for
example:
- Modify the Output walker to get the raw SQL via ``Query->getSQL()``
with interpolated parameters.
- Modify the AST to generate a Count Query to be used with a
paginator for any given DQL query.
- Modify the Output Walker to generate vendor-specific SQL
@@ -50,7 +51,7 @@ example:
- Modify the Output walker to pretty print the SQL for debugging
purposes.
In this cookbook-entry I will show examples of the first two
In this cookbook-entry I will show examples of the first three
points. There are probably much more use-cases.
Generic count query for pagination
@@ -101,8 +102,16 @@ The ``Paginate::count(Query $query)`` looks like:
{
static public function count(Query $query)
{
/** @var Query $countQuery */
$countQuery = clone $query;
/*
To avoid changing the $query passed into the method and to make sure a possibly existing
ResultSetMapping is discarded, we create a new query object any copy relevant data over.
*/
$countQuery = new Query($query->getEntityManager());
$countQuery->setDQL($query->getDQL());
$countQuery->setParameters(clone $query->getParameters());
foreach ($query->getHints() as $name => $value) {
$countQuery->setHint($name, $value);
}
$countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('DoctrineExtensions\Paginate\CountSqlWalker'));
$countQuery->setFirstResult(null)->setMaxResults(null);
@@ -111,7 +120,7 @@ The ``Paginate::count(Query $query)`` looks like:
}
}
It clones the query, resets the limit clause first and max results
This resets the limit clause first and max results
and registers the ``CountSqlWalker`` custom tree walker which
will modify the AST to execute a count query. The walkers
implementation is:
@@ -215,3 +224,39 @@ huge benefits with using vendor specific features. This would still
allow you write DQL queries instead of NativeQueries to make use of
vendor specific features.
Modifying the Output Walker to get the raw SQL with interpolated parameters
---------------------------------------------------------------------------
Sometimes we may want to log or trace the raw SQL being generated from its DQL
for profiling slow queries afterwards or audit queries that changed many rows
``$query->getSQL()`` will give us the prepared statement being passed to database
with all values of SQL parameters being replaced by positional ``?`` or named ``:name``
as parameters are interpolated into prepared statements by the database while executing the SQL.
``$query->getParameters()`` will give us details about SQL parameters that we've provided.
So we can create an output walker to interpolate all SQL parameters that will be
passed into prepared statement in PHP before database handle them internally:
.. literalinclude:: dql-custom-walkers/InterpolateParametersSQLOutputWalker.php
:language: php
Then you may get the raw SQL with this output walker:
.. code-block:: php
<?php
$query
->where('t.int IN (:ints)')->setParameter(':ints', [1, 2])
->orWhere('t.string IN (?0)')->setParameter(0, ['3', '4'])
->orWhere("t.bool = ?1")->setParameter('?1', true)
->orWhere("t.string = :string")->setParameter(':string', 'ABC')
->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, InterpolateParametersSQLOutputWalker::class)
->getSQL();
The where clause of the returned SQL should be like:
.. code-block:: sql
WHERE t0_.int IN (1, 2)
OR t0_.string IN ('3', '4')
OR t0_.bool = 1
OR t0_.string = 'ABC'

View File

@@ -0,0 +1,47 @@
<?php
use Doctrine\DBAL\ArrayParameterType;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Types\BooleanType;
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Query\AST;
use Doctrine\ORM\Query\SqlOutputWalker;
class InterpolateParametersSQLOutputWalker extends SqlOutputWalker
{
/** {@inheritdoc} */
public function walkInputParameter(AST\InputParameter $inputParam): string
{
$parameter = $this->getQuery()->getParameter($inputParam->name);
if ($parameter === null) {
return '?';
}
$value = $parameter->getValue();
/** @var ParameterType|ArrayParameterType|int|string $typeName */
/** @see \Doctrine\ORM\Query\ParameterTypeInferer::inferType() */
$typeName = $parameter->getType();
$platform = $this->getConnection()->getDatabasePlatform();
$processParameterType = static fn(ParameterType $type) => static fn($value): string =>
(match ($type) { /** @see Type::getBindingType() */
ParameterType::NULL => 'NULL',
ParameterType::INTEGER => $value,
ParameterType::BOOLEAN => (new BooleanType())->convertToDatabaseValue($value, $platform),
ParameterType::STRING, ParameterType::ASCII => $platform->quoteStringLiteral($value),
default => throw new ValueNotConvertible($value, $type->name)
});
if (is_string($typeName) && Type::hasType($typeName)) {
return Type::getType($typeName)->convertToDatabaseValue($value, $platform);
}
if ($typeName instanceof ParameterType) {
return $processParameterType($typeName)($value);
}
if ($typeName instanceof ArrayParameterType && is_array($value)) {
$type = ArrayParameterType::toElementParameterType($typeName);
return implode(', ', array_map($processParameterType($type), $value));
}
throw new ValueNotConvertible($value, $typeName);
}
}

View File

@@ -46,17 +46,18 @@ entities:
#[Entity]
class Article
{
const STATUS_VISIBLE = 'visible';
const STATUS_INVISIBLE = 'invisible';
public const STATUS_VISIBLE = 'visible';
public const STATUS_INVISIBLE = 'invisible';
#[Column(type: "string")]
private $status;
public function setStatus($status)
public function setStatus(string $status): void
{
if (!in_array($status, array(self::STATUS_VISIBLE, self::STATUS_INVISIBLE))) {
if (!in_array($status, [self::STATUS_VISIBLE, self::STATUS_INVISIBLE], true)) {
throw new \InvalidArgumentException("Invalid status");
}
$this->status = $status;
}
}
@@ -92,37 +93,33 @@ For example for the previous enum type:
class EnumVisibilityType extends Type
{
const ENUM_VISIBILITY = 'enumvisibility';
const STATUS_VISIBLE = 'visible';
const STATUS_INVISIBLE = 'invisible';
private const ENUM_VISIBILITY = 'enumvisibility';
private const STATUS_VISIBLE = 'visible';
private const STATUS_INVISIBLE = 'invisible';
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
{
return "ENUM('visible', 'invisible')";
}
public function convertToPHPValue($value, AbstractPlatform $platform)
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed
{
return $value;
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): string
{
if (!in_array($value, array(self::STATUS_VISIBLE, self::STATUS_INVISIBLE))) {
if (!in_array($value, [self::STATUS_VISIBLE, self::STATUS_INVISIBLE], true)) {
throw new \InvalidArgumentException("Invalid status");
}
return $value;
}
public function getName()
public function getName(): string
{
return self::ENUM_VISIBILITY;
}
public function requiresSQLCommentHint(AbstractPlatform $platform)
{
return true;
}
}
You can register this type with ``Type::addType('enumvisibility', 'MyProject\DBAL\EnumVisibilityType');``.
@@ -151,37 +148,33 @@ You can generalize this approach easily to create a base class for enums:
abstract class EnumType extends Type
{
protected $name;
protected $values = array();
protected $values = [];
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
{
$values = array_map(function($val) { return "'".$val."'"; }, $this->values);
$values = array_map(fn($val) => "'".$val."'", $this->values);
return "ENUM(".implode(", ", $values).")";
}
public function convertToPHPValue($value, AbstractPlatform $platform)
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed
{
return $value;
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): mixed
{
if (!in_array($value, $this->values)) {
if (!in_array($value, $this->values, true)) {
throw new \InvalidArgumentException("Invalid '".$this->name."' value.");
}
return $value;
}
public function getName()
public function getName(): string
{
return $this->name;
}
public function requiresSQLCommentHint(AbstractPlatform $platform)
{
return true;
}
}
With this base class you can define an enum as easily as:
@@ -194,5 +187,5 @@ With this base class you can define an enum as easily as:
class EnumVisibilityType extends EnumType
{
protected $name = 'enumvisibility';
protected $values = array('visible', 'invisible');
protected $values = ['visible', 'invisible'];
}

View File

@@ -13,7 +13,6 @@ If this documentation is not helping to answer questions you have about
Doctrine ORM don't panic. You can get help from different sources:
- There is a :doc:`FAQ <reference/faq>` with answers to frequent questions.
- The `Doctrine Mailing List <https://groups.google.com/group/doctrine-user>`_
- Slack chat room `#orm <https://www.doctrine-project.org/slack>`_
- Report a bug on `GitHub <https://github.com/doctrine/orm/issues>`_.
- On `StackOverflow <https://stackoverflow.com/questions/tagged/doctrine-orm>`_

View File

@@ -29,22 +29,11 @@ steps of configuration.
$config = new Configuration;
$config->setMetadataCache($metadataCache);
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']);
$config->setMetadataDriverImpl($driverImpl);
$config->setQueryCache($queryCache);
if (PHP_VERSION_ID > 80400) {
$config->enableNativeLazyObjects(true);
} else {
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
$config->setProxyNamespace('MyProject\Proxies');
if ($applicationMode === "development") {
$config->setAutoGenerateProxyClasses(true);
} else {
$config->setAutoGenerateProxyClasses(false);
}
}
$config->enableNativeLazyObjects(true);
$connection = DriverManager::getConnection([
'driver' => 'pdo_sqlite',
@@ -76,53 +65,6 @@ Configuration Options
The following sections describe all the configuration options
available on a ``Doctrine\ORM\Configuration`` instance.
Native Lazy Objects (**OPTIONAL**)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With PHP 8.4 we recommend that you use native lazy objects instead of
the code generation approach using the ``symfony/var-exporter`` Ghost trait.
With Doctrine 4, the minimal requirement will become PHP 8.4 and native lazy objects
will become the only approach to lazy loading.
.. code-block:: php
<?php
$config->enableNativeLazyObjects(true);
Proxy Directory
~~~~~~~~~~~~~~~
Required except if you use native lazy objects with PHP 8.4.
This setting will be removed in the future.
.. code-block:: php
<?php
$config->setProxyDir($dir);
$config->getProxyDir();
Gets or sets the directory where Doctrine generates any proxy
classes. For a detailed explanation on proxy classes and how they
are used in Doctrine, refer to the "Proxy Objects" section further
down.
Proxy Namespace
~~~~~~~~~~~~~~~
Required except if you use native lazy objects with PHP 8.4.
This setting will be removed in the future.
.. code-block:: php
<?php
$config->setProxyNamespace($namespace);
$config->getProxyNamespace();
Gets or sets the namespace to use for generated proxy classes. For
a detailed explanation on proxy classes and how they are used in
Doctrine, refer to the "Proxy Objects" section further down.
Metadata Driver (**REQUIRED**)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -154,15 +96,59 @@ The attribute driver can be injected in the ``Doctrine\ORM\Configuration``:
<?php
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities']);
$config->setMetadataDriverImpl($driverImpl);
The path information to the entities is required for the attribute
driver, because otherwise mass-operations on all entities through
the console could not work correctly. All of metadata drivers
accept either a single directory as a string or an array of
directories. With this feature a single driver can support multiple
directories of Entities.
the console could not work correctly. Metadata drivers can accept either
a single directory as a string or an array of directories.
AttributeDriver also accepts ``Doctrine\Persistence\Mapping\Driver\ClassLocator``,
allowing one to customize file discovery logic. You may choose to use Symfony Finder, or
utilize directory scan with ``FileClassLocator::createFromDirectories()``:
.. code-block:: php
<?php
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
use Doctrine\Persistence\Mapping\Driver\FileClassLocator;
$paths = ['/path/to/lib/MyProject/Entities'];
$classLocator = FileClassLocator::createFromDirectories($paths);
$driverImpl = new AttributeDriver($classLocator);
$config->setMetadataDriverImpl($driverImpl);
With this feature, you're empowered to provide a fine-grained iterator of only necessary
files to the Driver. For example, if you are using Vertical Slice architecture, you can
exclude ``*Test.php``, ``*Controller.php``, ``*Service.php``, etc.:
.. code-block:: php
<?php
use Symfony\Component\Finder\Finder;
$finder = new Finder()->files()->in($paths)
->name('*.php')
->notName(['*Test.php', '*Controller.php', '*Service.php']);
$classLocator = new FileClassLocator($finder);
If you know the list of class names you want to track, use
``Doctrine\Persistence\Mapping\Driver\ClassNames``:
.. code-block:: php
<?php
use Doctrine\Persistence\Mapping\Driver\ClassNames;
use App\Entity\{Article, Book};
$entityClasses = [Article::class, Book::class];
$classLocator = new ClassNames($entityClasses);
$driverImpl = new AttributeDriver($classLocator);
$config->setMetadataDriverImpl($driverImpl);
Metadata Cache (**RECOMMENDED**)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -222,63 +208,6 @@ Gets or sets the logger to use for logging all SQL statements
executed by Doctrine. The logger class must implement the
deprecated ``Doctrine\DBAL\Logging\SQLLogger`` interface.
Auto-generating Proxy Classes (**OPTIONAL**)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This setting is not required if you use native lazy objects with PHP 8.4
and will be removed in the future.
Proxy classes can either be generated manually through the Doctrine
Console or automatically at runtime by Doctrine. The configuration
option that controls this behavior is:
.. code-block:: php
<?php
$config->setAutoGenerateProxyClasses($mode);
Possible values for ``$mode`` are:
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_NEVER``
Never autogenerate a proxy. You will need to generate the proxies
manually, for this use the Doctrine Console like so:
.. code-block:: php
$ ./doctrine orm:generate-proxies
When you do this in a development environment,
be aware that you may get class/file not found errors if certain proxies
are not yet generated. You may also get failing lazy-loads if new
methods were added to the entity class that are not yet in the proxy class.
In such a case, simply use the Doctrine Console to (re)generate the
proxy classes.
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_ALWAYS``
Always generates a new proxy in every request and writes it to disk.
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS``
Generate the proxy class when the proxy file does not exist.
This strategy causes a file exists call whenever any proxy is
used the first time in a request.
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_EVAL``
Generate the proxy classes and evaluate them on the fly via eval(),
avoiding writing the proxies to disk.
This strategy is only sane for development.
In a production environment, it is highly recommended to use
AUTOGENERATE_NEVER to allow for optimal performances. The other
options are interesting in development environment.
``setAutoGenerateProxyClasses`` can accept a boolean
value. This is still possible, ``FALSE`` being equivalent to
AUTOGENERATE_NEVER and ``TRUE`` to AUTOGENERATE_ALWAYS.
Development vs Production Configuration
---------------------------------------
@@ -302,7 +231,7 @@ requests.
Connection
----------
The ``$connection`` passed as the first argument to he constructor of
The ``$connection`` passed as the first argument to the constructor of
``EntityManager`` has to be an instance of ``Doctrine\DBAL\Connection``.
You can use the factory ``Doctrine\DBAL\DriverManager::getConnection()``
to create such a connection. The DBAL configuration is explained in the
@@ -394,55 +323,6 @@ transparently initialize itself on first access.
This will override the 'fetch' option specified in the mapping for
that association, but only for that query.
Generating Proxy classes
~~~~~~~~~~~~~~~~~~~~~~~~
In a production environment, it is highly recommended to use
``AUTOGENERATE_NEVER`` to allow for optimal performances.
However you will be required to generate the proxies manually
using the Doctrine Console:
.. code-block:: php
$ ./doctrine orm:generate-proxies
The other options are interesting in development environment:
- ``AUTOGENERATE_ALWAYS`` will require you to create and configure
a proxy directory. Proxies will be generated and written to file
on each request, so any modification to your code will be acknowledged.
- ``AUTOGENERATE_FILE_NOT_EXISTS`` will not overwrite an existing
proxy file. If your code changes, you will need to regenerate the
proxies manually.
- ``AUTOGENERATE_EVAL`` will regenerate each proxy on each request,
but without writing them to disk.
Autoloading Proxies
-------------------
When you deserialize proxy objects from the session or any other storage
it is necessary to have an autoloading mechanism in place for these classes.
For implementation reasons Proxy class names are not PSR-0 compliant. This
means that you have to register a special autoloader for these classes:
.. code-block:: php
<?php
use Doctrine\ORM\Proxy\Autoloader;
$proxyDir = "/path/to/proxies";
$proxyNamespace = "MyProxies";
Autoloader::register($proxyDir, $proxyNamespace);
If you want to execute additional logic to intercept the proxy file not found
state you can pass a closure as the third argument. It will be called with
the arguments proxydir, namespace and className when the proxy file could not
be found.
Multiple Metadata Sources
-------------------------

View File

@@ -18,7 +18,7 @@ well.
Requirements
------------
Doctrine ORM requires a minimum of PHP 8.1. For greatly improved
Doctrine ORM requires a minimum of PHP 8.4. For greatly improved
performance it is also recommended that you use APC with PHP.
Doctrine ORM Packages
@@ -79,8 +79,8 @@ Entities
An entity is a lightweight, persistent domain object. An entity can
be any regular PHP class observing the following restrictions:
- An entity class must not be final nor read-only but
it may contain final methods or read-only properties.
- An entity class can be final or read-only. It may contain final
methods or read-only properties too.
- Any two entity classes in a class hierarchy that inherit
directly or indirectly from one another must not have a mapped
property with the same name. That is, if B inherits from A then B
@@ -167,7 +167,7 @@ recommended, at least not as long as an entity instance still holds
references to proxy objects or is still managed by an EntityManager.
By default, serializing proxy objects does not initialize them. On
unserialization, resulting objects are detached from the entity
manager and cannot be initialiazed anymore. You can implement the
manager and cannot be initialized anymore. You can implement the
``__serialize()`` method if you want to change that behavior, but
then you need to ensure that you won't generate large serialized
object graphs and take care of circular associations.

View File

@@ -175,6 +175,10 @@ Optional parameters:
- **unique**: Boolean value to determine if the value of the column
should be unique across all rows of the underlying entities table.
- **index**: Boolean value to generate an index for this column.
For more advanced usages, take a look at :ref:`#[Index] <attrref_index>`.
If not specified, default value is ``false``.
- **nullable**: Determines if NULL values allowed for this column.
If not specified, default value is ``false``.
@@ -245,6 +249,9 @@ Examples:
#[Column(type: "string", length: 32, unique: true, nullable: false)]
protected $username;
#[Column(type: "string", index: true)]
protected $firstName;
#[Column(type: "string", columnDefinition: "CHAR(2) NOT NULL")]
protected $country;
@@ -661,11 +668,6 @@ and in the Context of a :ref:`#[ManyToMany] <attrref_manytomany>`. If this attri
are missing they will be computed considering the field's name and the current
:doc:`naming strategy <namingstrategy>`.
The ``#[InverseJoinColumn]`` is the same as ``#[JoinColumn]`` and is used in the context
of a ``#[ManyToMany]`` attribute declaration to specifiy the details of the join table's
column information used for the join to the inverse entity. This is only required
on PHP 8.0, where nested attributes are not yet supported.
Optional parameters:
- **name**: Column name that holds the foreign key identifier for

View File

@@ -182,6 +182,37 @@ Here is a complete list of ``Column``s attributes (all optional):
- ``options``: Key-value pairs of options that get passed
to the underlying database platform when generating DDL statements.
Specifying default values
~~~~~~~~~~~~~~~~~~~~~~~~~
While it is possible to specify default values for properties in your
PHP class, Doctrine also allows you to specify default values for
database columns using the ``default`` key in the ``options`` array of
the ``Column`` attribute.
When using XML, you can specify object instances using the ``<object>``
element:
.. code-block:: xml
<field name="createdAt" type="datetime" insertable="false" updatable="false">
<options>
<option name="default">
<object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp"/>
</option>
</options>
</field>
The ``<object>`` element requires a ``class`` attribute specifying the
fully qualified class name to instantiate.
.. configuration-block::
.. literalinclude:: basic-mapping/DefaultValues.php
:language: attribute
.. literalinclude:: basic-mapping/default-values.xml
:language: xml
.. _reference-php-mapping-types:
PHP Types Mapping
@@ -389,17 +420,19 @@ Here is the list of possible generation strategies:
- ``AUTO`` (default): Tells Doctrine to pick the strategy that is
preferred by the used database platform. The preferred strategies
are ``IDENTITY`` for MySQL, SQLite, MsSQL and SQL Anywhere and, for
historical reasons, ``SEQUENCE`` for Oracle and PostgreSQL. This
strategy provides full portability.
are ``IDENTITY`` for MySQL, SQLite, MsSQL, SQL Anywhere and
PostgreSQL (on DBAL 4) and, for historical reasons, ``SEQUENCE``
for Oracle and PostgreSQL (on DBAL 3). This strategy provides
full portability.
- ``IDENTITY``: Tells Doctrine to use special identity columns in
the database that generate a value on insertion of a row. This
strategy does currently not provide full portability and is
supported by the following platforms: MySQL/SQLite/SQL Anywhere
(``AUTO_INCREMENT``), MSSQL (``IDENTITY``) and PostgreSQL (``SERIAL``).
(``AUTO_INCREMENT``), MSSQL (``IDENTITY``) and PostgreSQL (``SERIAL``
on DBAL 3, ``GENERATED BY DEFAULT AS IDENTITY`` on DBAL 4).
- ``SEQUENCE``: Tells Doctrine to use a database sequence for ID
generation. This strategy does currently not provide full
portability. Sequences are supported by Oracle, PostgreSql and
portability. Sequences are supported by Oracle, PostgreSQL and
SQL Anywhere.
- ``NONE``: Tells Doctrine that the identifiers are assigned (and
thus generated) by your code. The assignment must take place before

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use DateTime;
use Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
#[Entity]
class Message
{
#[Column(options: ['default' => 'Hello World!'])]
private string $text;
#[Column(options: ['default' => new CurrentTimestamp()], insertable: false, updatable: false)]
private DateTime $createdAt;
}

View File

@@ -0,0 +1,16 @@
<doctrine-mapping>
<entity name="Message">
<field name="text">
<options>
<option name="default">Hello World!</option>
</options>
</field>
<field name="createdAt" insertable="false" updatable="false">
<options>
<option name="default">
<object class="Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp"/>
</option>
</options>
</field>
</entity>
</doctrine-mapping>

View File

@@ -56,7 +56,8 @@ access point to ORM functionality provided by Doctrine.
'dbname' => 'foo',
];
$config = ORMSetup::createAttributeMetadataConfiguration($paths, $isDevMode);
$config = ORMSetup::createAttributeMetadataConfig($paths, $isDevMode);
// on PHP < 8.4, use ORMSetup::createAttributeMetadataConfiguration() instead
$connection = DriverManager::getConnection($dbParams, $config);
$entityManager = new EntityManager($connection, $config);
@@ -66,7 +67,8 @@ Or if you prefer XML:
<?php
$paths = ['/path/to/xml-mappings'];
$config = ORMSetup::createXMLMetadataConfiguration($paths, $isDevMode);
$config = ORMSetup::createXMLMetadataConfig($paths, $isDevMode);
// on PHP < 8.4, use ORMSetup::createXMLMetadataConfiguration() instead
$connection = DriverManager::getConnection($dbParams, $config);
$entityManager = new EntityManager($connection, $config);

View File

@@ -490,7 +490,7 @@ where you can generate an arbitrary join with the following syntax:
.. code-block:: php
<?php
$query = $em->createQuery('SELECT u FROM User u JOIN Banlist b WITH u.email = b.email');
$query = $em->createQuery('SELECT u FROM User u JOIN Banlist b ON u.email = b.email');
With an arbitrary join the result differs from the joins using a mapped property.
The result of an arbitrary join is an one dimensional array with a mix of the entity from the ``SELECT``
@@ -513,13 +513,15 @@ it loads all the related ``Banlist`` objects corresponding to this ``User``. Thi
when the DQL is switched to an arbitrary join.
.. note::
The differences between WHERE, WITH and HAVING clauses may be
The differences between WHERE, WITH, ON and HAVING clauses may be
confusing.
- WHERE is applied to the results of an entire query
- WITH is applied to a join as an additional condition. For
arbitrary joins (SELECT f, b FROM Foo f, Bar b WITH f.id = b.id)
the WITH is required, even if it is 1 = 1
- ON is applied to arbitrary joins as the join condition. For
arbitrary joins (SELECT f, b FROM Foo f, Bar b ON f.id = b.id)
the ON is required, even if it is 1 = 1. WITH is also
supported as alternative keyword for that case for BC reasons.
- WITH is applied to an association join as an additional condition.
- HAVING is applied to the results of a query after
aggregation (GROUP BY)
@@ -1409,8 +1411,7 @@ Result Cache API:
$query->setResultCacheDriver(new ApcCache());
$query->useResultCache(true)
->setResultCacheLifeTime(3600);
$query->enableResultCache(3600);
$result = $query->getResult(); // cache miss
@@ -1420,8 +1421,8 @@ Result Cache API:
$query->setResultCacheId('my_query_result');
$result = $query->getResult(); // saved in given result cache id.
// or call useResultCache() with all parameters:
$query->useResultCache(true, 3600, 'my_query_result');
// or call enableResultCache() with all parameters:
$query->enableResultCache(3600, 'my_query_result');
$result = $query->getResult(); // cache hit!
// Introspection
@@ -1699,9 +1700,14 @@ From, Join and Index by
SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration
RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy]
Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" (JoinAssociationDeclaration | RangeVariableDeclaration) ["WITH" ConditionalExpression]
Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" (JoinAssociationDeclaration ["WITH" ConditionalExpression] | RangeVariableDeclaration [("ON" | "WITH") ConditionalExpression])
IndexBy ::= "INDEX" "BY" SingleValuedPathExpression
.. note::
Using the ``WITH`` keyword for the ``ConditionalExpression`` of a
``RangeVariableDeclaration`` is deprecated and will be removed in
ORM 4.0. Use the ``ON`` keyword instead.
Select Expressions
~~~~~~~~~~~~~~~~~~

View File

@@ -18,30 +18,6 @@ In your mapping configuration, the column definition (for example, the
the ``charset`` and ``collation``. The default values are ``utf8`` and
``utf8_unicode_ci``, respectively.
Entity Classes
--------------
How can I add default values to a column?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Doctrine does not support to set the default values in columns through the "DEFAULT" keyword in SQL.
This is not necessary however, you can just use your class properties as default values. These are then used
upon insert:
.. code-block:: php
class User
{
private const STATUS_DISABLED = 0;
private const STATUS_ENABLED = 1;
private string $algorithm = "sha1";
/** @var self::STATUS_* */
private int $status = self::STATUS_DISABLED;
}
.
Mapping
-------

View File

@@ -30,7 +30,7 @@ table alias of the SQL table of the entity.
For the filter to correctly function, the following rules must be followed. Failure to do so will lead to unexpected results from the query cache.
1. Parameters for the query should be set on the filter object by ``SQLFilter#setParameter()`` before the filter is used by the ORM ( i.e. do not set parameters inside ``SQLFilter#addFilterConstraint()`` function ).
2. The filter must be deterministic. Don't change the values base on external inputs.
2. The filter must be deterministic. Don't change the values based on external inputs.
The ``SQLFilter#getParameter()`` function takes care of the proper quoting of parameters.

View File

@@ -208,6 +208,22 @@ Example:
// ...
}
.. code-block:: xml
<doctrine-mapping>
<entity name="MyProject\Model\Person" inheritance-type="SINGLE_TABLE">
<discriminator-column name="discr" type="string" />
<discriminator-map>
<discriminator-mapping value="person" class="MyProject\Model\Person"/>
<discriminator-mapping value="employee" class="MyProject\Model\Employee"/>
</discriminator-map>
</entity>
</doctrine-mapping>
<doctrine-mapping>
<entity name="MyProject\Model\Employee">
</entity>
</doctrine-mapping>
In this example, the ``#[DiscriminatorMap]`` specifies that in the
discriminator column, a value of "person" identifies a row as being of type

View File

@@ -178,6 +178,14 @@ internally by the ORM currently refers to fields by their name only, without tak
class containing the field into consideration. This makes it impossible to keep separate
mapping configuration for both fields.
Apart from that, in the case of having multiple ``private`` fields of the same name within
the class hierarchy an entity or mapped superclass, the Collection filtering API cannot determine
the right field to look at. Even if only one of these fields is actually mapped, the ``ArrayCollection``
will not be able to tell, since it does not have access to any metadata.
Thus, to avoid problems in this regard, it is best to avoid having multiple ``private`` fields of the
same name in class hierarchies containing entity and mapped superclasses.
Known Issues
------------

View File

@@ -209,6 +209,7 @@ Field & Association Getters
- ``isUniqueField($fieldName)``
- ``isNullable($fieldName)``
- ``isIndexed($fieldName)``
- ``getColumnName($fieldName)``
- ``getFieldMapping($fieldName)``
- ``getAssociationMapping($fieldName)``

View File

@@ -344,10 +344,10 @@ the Query object which can be retrieved from ``EntityManager#createQuery()``.
Executing a Query
^^^^^^^^^^^^^^^^^
The QueryBuilder is a builder object only - it has no means of actually
executing the Query. Additionally a set of parameters such as query hints
cannot be set on the QueryBuilder itself. This is why you always have to convert
a querybuilder instance into a Query object:
The QueryBuilder is only a builder object - it has no means of actually
executing the Query. Additional functionality, such as enabling the result cache,
cannot be set on the QueryBuilder itself. This is why you must always convert
a QueryBuilder instance into a Query object:
.. code-block:: php
@@ -355,9 +355,8 @@ a querybuilder instance into a Query object:
// $qb instanceof QueryBuilder
$query = $qb->getQuery();
// Set additional Query options
$query->setQueryHint('foo', 'bar');
$query->useResultCache('my_cache_id');
// Enable the result cache
$query->enableResultCache(3600, 'my_custom_id');
// Execute Query
$result = $query->getResult();
@@ -555,6 +554,24 @@ using ``addCriteria``:
$qb->addCriteria($criteria);
// then execute your query like normal
Adding hints to a Query
^^^^^^^^^^^^^^^^^^^^^^^
You can also set query hints to a QueryBuilder by using ``setHint``:
.. code-block:: php
<?php
// ...
// $qb instanceof QueryBuilder
$qb->setHint('hintName', 'hintValue');
// then execute your query like normal
The query hint can hold anything the usual query hints can hold
except null. Those hints will be applied to the query when the
query is created.
Low Level API
^^^^^^^^^^^^^

View File

@@ -44,7 +44,7 @@ Something like below for an entity region:
If the entity holds a collection that also needs to be cached.
An collection region could look something like:
A collection region could look something like:
.. code-block:: php
@@ -133,7 +133,7 @@ Caching mode
* Read Write cache employs locks before update/delete.
* Use if data needs to be updated.
* Slowest strategy.
* To use it a the cache region implementation must support locking.
* To use it the cache region implementation must support locking.
Built-in cached persisters
@@ -518,7 +518,7 @@ DELETE / UPDATE queries
DQL UPDATE / DELETE statements are ported directly into a database and bypass
the second-level cache.
Entities that are already cached will NOT be invalidated.
However the cached data could be evicted using the cache API or an special query hint.
However the cached data could be evicted using the cache API or a special query hint.
Execute the ``UPDATE`` and invalidate ``all cache entries`` using ``Query::HINT_CACHE_EVICT``

View File

@@ -118,7 +118,7 @@ entity might look like this:
}
}
Now the possiblity of mass-assignment exists on this entity and can
Now the possibility of mass-assignment exists on this entity and can
be exploited by attackers to set the "isAdmin" flag to true on any
object when you pass the whole request data to this method like:

View File

@@ -22,7 +22,7 @@ have to register them yourself.
All the commands of the Doctrine Console require access to the
``EntityManager``. You have to inject it into the console application.
Here is an example of a the project-specific ``bin/doctrine`` binary.
Here is an example of a project-specific ``bin/doctrine`` binary.
.. code-block:: php
@@ -83,8 +83,6 @@ The following Commands are currently available:
cache drivers.
- ``orm:clear-cache:result`` Clear result cache of the various
cache drivers.
- ``orm:generate-proxies`` Generates proxy classes for entity
classes.
- ``orm:run-dql`` Executes arbitrary DQL directly from the command
line.
- ``orm:schema-tool:create`` Processes the schema and either
@@ -96,6 +94,10 @@ The following Commands are currently available:
- ``orm:schema-tool:update`` Processes the schema and either
update the database schema of EntityManager Storage Connection or
generate the SQL output.
- ``orm:debug:event-manager`` Lists event listeners for an entity
manager, optionally filtered by event name.
- ``orm:debug:entity-listeners`` Lists entity listeners for a given
entity, optionally filtered by event name.
The following alias is defined:

View File

@@ -112,7 +112,6 @@ of several common elements:
<indexes>
<index name="name_idx" columns="name"/>
<index columns="user_email"/>
</indexes>
<unique-constraints>
@@ -131,7 +130,7 @@ of several common elements:
</id>
<field name="name" column="name" type="string" length="50" nullable="true" unique="true" />
<field name="email" column="user_email" type="string" column-definition="CHAR(32) NOT NULL" />
<field name="email" column="user_email" type="string" index="true" column-definition="CHAR(32) NOT NULL" />
<one-to-one field="address" target-entity="Address" inversed-by="user">
<cascade><cascade-remove /></cascade>
@@ -255,6 +254,8 @@ Optional attributes:
only.
- unique - Should this field contain a unique value across the
table? Defaults to false.
- index - Should an index be created for this column? Defaults to
false.
- nullable - Should this field allow NULL as a value? Defaults to
false.
- insertable - Should this field be inserted? Defaults to true.

View File

@@ -5,8 +5,6 @@
:depth: 3
tutorials/getting-started
tutorials/getting-started-database
tutorials/getting-started-models
tutorials/working-with-indexed-associations
tutorials/extra-lazy-associations
tutorials/composite-primary-keys

View File

@@ -1,26 +0,0 @@
Getting Started: Database First
===============================
.. note:: *Development Workflows*
When you :doc:`Code First <getting-started>`, you
start with developing Objects and then map them onto your database. When
you :doc:`Model First <getting-started-models>`, you are modelling your application using tools (for
example UML) and generate database schema and PHP code from this model.
When you have a Database First, you already have a database schema
and generate the corresponding PHP code from it.
.. note::
This getting started guide is in development.
Development of new applications often starts with an existing database schema.
When the database schema is the starting point for your application, then
development is said to use the *Database First* approach to Doctrine.
In this workflow you would modify the database schema first and then
regenerate the PHP code to use with this schema. You need a flexible
code-generator for this task.
We spun off a subproject, Doctrine CodeGenerator, that will fill this gap and
allow you to do *Database First* development.

View File

@@ -1,24 +0,0 @@
Getting Started: Model First
============================
.. note:: *Development Workflows*
When you :doc:`Code First <getting-started>`, you
start with developing Objects and then map them onto your database. When
you Model First, you are modelling your application using tools (for
example UML) and generate database schema and PHP code from this model.
When you have a :doc:`Database First <getting-started-database>`, then you already have a database schema
and generate the corresponding PHP code from it.
.. note::
This getting started guide is in development.
There are applications when you start with a high-level description of the
model using modelling tools such as UML. Modelling tools could also be Excel,
XML or CSV files that describe the model in some structured way. If your
application is using a modelling tool, then the development workflow is said to
be a *Model First* approach to Doctrine2.
In this workflow you always change the model description and then regenerate
both PHP code and database schema from this model.

View File

@@ -49,8 +49,7 @@ An entity contains persistable properties. A persistable property
is an instance variable of the entity that is saved into and retrieved from the database
by Doctrine's data mapping capabilities.
An entity class must not be final nor read-only, although
it can contain final methods or read-only properties.
An entity class can be final or read-only. It may contain final methods or read-only properties too.
An Example Model: Bug Tracker
-----------------------------
@@ -138,12 +137,12 @@ step:
require_once "vendor/autoload.php";
// Create a simple "default" Doctrine ORM configuration for Attributes
$config = ORMSetup::createAttributeMetadataConfiguration(
$config = ORMSetup::createAttributeMetadataConfig( // on PHP < 8.4, use ORMSetup::createAttributeMetadataConfiguration()
paths: [__DIR__ . '/src'],
isDevMode: true,
);
// or if you prefer XML
// $config = ORMSetup::createXMLMetadataConfiguration(
// $config = ORMSetup::createXMLMetadataConfig( // on PHP < 8.4, use ORMSetup::createXMLMetadataConfiguration()
// paths: [__DIR__ . '/config/xml'],
// isDevMode: true,
//);
@@ -534,7 +533,7 @@ the ``id`` tag. It has a ``generator`` tag nested inside, which
specifies that the primary key generation mechanism should automatically
use the database platform's native id generation strategy (for
example, AUTO INCREMENT in the case of MySql, or Sequences in the
case of PostgreSql and Oracle).
case of PostgreSQL and Oracle).
Now that we have defined our first entity and its metadata,
let's update the database schema:
@@ -1287,7 +1286,7 @@ The console output of this script is then:
result set to retrieve entities from the database. DQL boils down to a
Native SQL statement and a ``ResultSetMapping`` instance itself. Using
Native SQL you could even use stored procedures for data retrieval, or
make use of advanced non-portable database queries like PostgreSql's
make use of advanced non-portable database queries like PostgreSQL's
recursive queries.

View File

@@ -155,10 +155,20 @@
</xs:restriction>
</xs:simpleType>
<xs:complexType name="object">
<xs:attribute name="class" type="xs:string" use="required"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="option" mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="option" type="orm:option"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
<xs:choice minOccurs="0" maxOccurs="1">
<xs:element name="object" type="orm:object"/>
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="option" type="orm:option"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
</xs:sequence>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required"/>
<xs:anyAttribute namespace="##other"/>
@@ -243,6 +253,7 @@
<xs:attribute name="length" type="xs:NMTOKEN" />
<xs:attribute name="unique" type="xs:boolean" default="false" />
<xs:attribute name="nullable" type="xs:boolean" default="false" />
<xs:attribute name="index" type="xs:boolean" default="false" />
<xs:attribute name="insertable" type="xs:boolean" default="true" />
<xs:attribute name="updatable" type="xs:boolean" default="true" />
<xs:attribute name="generated" type="orm:generated-type" default="NEVER" />

View File

@@ -11,7 +11,7 @@
<!-- Ignore warnings, show progress of the run and show sniff names -->
<arg value="nps"/>
<config name="php_version" value="80100"/>
<config name="php_version" value="80400"/>
<file>src</file>
<file>tests</file>
@@ -50,8 +50,6 @@
</rule>
<rule ref="PSR1.Classes.ClassDeclaration.MultipleClasses">
<exclude-pattern>src/Mapping/Driver/LoadMappingFileImplementation.php</exclude-pattern>
<exclude-pattern>src/Mapping/GetReflectionClassImplementation.php</exclude-pattern>
<exclude-pattern>tests/*</exclude-pattern>
</rule>
@@ -210,12 +208,6 @@
<exclude-pattern>tests/Tests/Models/DDC1590/DDC1590User.php</exclude-pattern>
</rule>
<rule ref="Squiz.Classes.ValidClassName.NotCamelCaps">
<!-- we need to test what happens with an stdClass proxy -->
<exclude-pattern>tests/Tests/Proxy/DefaultProxyClassNameResolverTest.php</exclude-pattern>
</rule>
<rule ref="Squiz.Commenting.FunctionComment.WrongStyle">
<!-- https://github.com/squizlabs/PHP_CodeSniffer/issues/1961 -->
<exclude-pattern>tests/Tests/Mocks/DatabasePlatformMock.php</exclude-pattern>

View File

@@ -1,17 +1,5 @@
parameters:
ignoreErrors:
-
message: '#^Expression "\$setCacheEntry\(\$data\)" on a separate line does not do anything\.$#'
identifier: expr.resultUnused
count: 1
path: src/AbstractQuery.php
-
message: '#^Expression "\$setCacheEntry\(\$stmt\)" on a separate line does not do anything\.$#'
identifier: expr.resultUnused
count: 1
path: src/AbstractQuery.php
-
message: '#^Method Doctrine\\ORM\\AbstractQuery\:\:getParameter\(\) should return Doctrine\\ORM\\Query\\Parameter\|null but returns Doctrine\\ORM\\Query\\Parameter\|false\|null\.$#'
identifier: return.type
@@ -234,12 +222,6 @@ parameters:
count: 1
path: src/Cache/DefaultQueryCache.php
-
message: '#^Parameter \#1 \$result of class Doctrine\\ORM\\Cache\\QueryCacheEntry constructor expects array\<string, mixed\>, array\<int\|string, array\<string, array\<mixed\>\>\> given\.$#'
identifier: argument.type
count: 1
path: src/Cache/DefaultQueryCache.php
-
message: '#^Parameter \#2 \$key of method Doctrine\\ORM\\Cache\\Logging\\CacheLogger\:\:entityCacheHit\(\) expects Doctrine\\ORM\\Cache\\EntityCacheKey, Doctrine\\ORM\\Cache\\CacheKey given\.$#'
identifier: argument.type
@@ -516,6 +498,12 @@ parameters:
count: 1
path: src/Cache/TimestampQueryCacheValidator.php
-
message: '#^Call to function is_a\(\) with arguments class\-string\<Doctrine\\ORM\\EntityRepository\>, ''Doctrine\\\\ORM\\\\EntityRepository'' and true will always evaluate to true\.$#'
identifier: function.alreadyNarrowedType
count: 1
path: src/Configuration.php
-
message: '#^Method Doctrine\\ORM\\Configuration\:\:getDefaultRepositoryClassName\(\) return type with generic class Doctrine\\ORM\\EntityRepository does not specify its types\: T$#'
identifier: missingType.generics
@@ -558,12 +546,6 @@ parameters:
count: 1
path: src/Decorator/EntityManagerDecorator.php
-
message: '#^Call to an undefined method object\:\:setEntityManager\(\)\.$#'
identifier: method.notFound
count: 1
path: src/EntityManager.php
-
message: '#^Method Doctrine\\ORM\\EntityManager\:\:checkLockRequirements\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
@@ -637,7 +619,7 @@ parameters:
path: src/EntityRepository.php
-
message: '#^Method Doctrine\\ORM\\EntityRepository\:\:matching\(\) should return Doctrine\\Common\\Collections\\AbstractLazyCollection\<int, T of object\>&Doctrine\\Common\\Collections\\Selectable\<int, T of object\> but returns Doctrine\\ORM\\LazyCriteriaCollection\<\(int\|string\), object\>\.$#'
message: '#^Method Doctrine\\ORM\\EntityRepository\:\:matching\(\) should return Doctrine\\Common\\Collections\\AbstractLazyCollection\<int, T of object\> but returns Doctrine\\ORM\\LazyCriteriaCollection\<\(int\|string\), object\>\.$#'
identifier: return.type
count: 1
path: src/EntityRepository.php
@@ -733,13 +715,13 @@ parameters:
path: src/Internal/Hydration/AbstractHydrator.php
-
message: '#^Parameter &\$id by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, string\>, array\<int\|string, string\> given\.$#'
message: '#^Parameter &\$id by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, string\>, array\<string\> given\.$#'
identifier: parameterByRef.type
count: 1
path: src/Internal/Hydration/AbstractHydrator.php
-
message: '#^Parameter &\$nonemptyComponents by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, bool\>, array\<int\|string, bool\> given\.$#'
message: '#^Parameter &\$nonemptyComponents by\-ref type of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:gatherRowData\(\) expects array\<string, bool\>, array\<bool\> given\.$#'
identifier: parameterByRef.type
count: 1
path: src/Internal/Hydration/AbstractHydrator.php
@@ -834,6 +816,12 @@ parameters:
count: 1
path: src/Internal/HydrationCompleteHandler.php
-
message: '#^Offset int\|null might not exist on array\<int, object\>\.$#'
identifier: offsetAccess.notFound
count: 1
path: src/Internal/StronglyConnectedComponents.php
-
message: '#^Property Doctrine\\ORM\\Internal\\StronglyConnectedComponents\:\:\$representingNodes \(array\<int, object\>\) does not accept array\<int\|string, object\>\.$#'
identifier: assign.propertyType
@@ -954,12 +942,6 @@ parameters:
count: 4
path: src/Mapping/ClassMetadata.php
-
message: '#^If condition is always true\.$#'
identifier: if.alwaysTrue
count: 1
path: src/Mapping/ClassMetadata.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\ClassMetadata\:\:inlineEmbeddable\(\) has parameter \$embeddable with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
@@ -1080,6 +1062,12 @@ parameters:
count: 1
path: src/Mapping/ClassMetadata.php
-
message: '#^Template type T is declared as covariant, but occurs in invariant position in return type of method Doctrine\\ORM\\Mapping\\ClassMetadata\:\:getReflectionClass\(\)\.$#'
identifier: generics.variance
count: 1
path: src/Mapping/ClassMetadata.php
-
message: '#^Unable to resolve the template type C in call to method Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:fullyQualifiedClassName\(\)$#'
identifier: argument.templateType
@@ -1314,6 +1302,12 @@ parameters:
count: 1
path: src/Mapping/DefaultQuoteStrategy.php
-
message: '#^Expression on left side of \?\? is not nullable\.$#'
identifier: nullCoalesce.expr
count: 1
path: src/Mapping/Driver/AttributeDriver.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\AttributeDriver\:\:isRepeatedPropertyDeclaration\(\) has parameter \$metadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
@@ -1332,132 +1326,6 @@ parameters:
count: 1
path: src/Mapping/Driver/AttributeDriver.php
-
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencedColumnNames\(\)\.$#'
identifier: method.notFound
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencedTableName\(\)\.$#'
identifier: method.notFound
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencingColumnNames\(\)\.$#'
identifier: method.notFound
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\Index\:\:getIndexedColumns\(\)\.$#'
identifier: method.notFound
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\Table\:\:getPrimaryKeyConstraint\(\)\.$#'
identifier: method.notFound
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Call to method getColumnName\(\) on an unknown class Doctrine\\DBAL\\Schema\\Index\\IndexedColumn\.$#'
identifier: class.notFound
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Call to method getColumnNames\(\) on an unknown class Doctrine\\DBAL\\Schema\\PrimaryKeyConstraint\.$#'
identifier: class.notFound
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Call to method toString\(\) on an unknown class Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName\.$#'
identifier: class.notFound
count: 5
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Cannot call method getName\(\) on Doctrine\\DBAL\\Schema\\Column\|false\.$#'
identifier: method.nonObject
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Class Doctrine\\DBAL\\Schema\\Index\\IndexType not found\.$#'
identifier: class.notFound
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Class Doctrine\\DBAL\\Schema\\PrimaryKeyConstraint not found\.$#'
identifier: class.notFound
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Instanceof between Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\> and Doctrine\\ORM\\Mapping\\ClassMetadata will always evaluate to true\.$#'
identifier: instanceof.alwaysTrue
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:__construct\(\) has parameter \$sm with generic class Doctrine\\DBAL\\Schema\\AbstractSchemaManager but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:buildFieldMappings\(\) has parameter \$metadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:buildIndexes\(\) has parameter \$metadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:buildToOneAssociationMappings\(\) has parameter \$metadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:getClassNameForTable\(\) should return class\-string but returns string\.$#'
identifier: return.type
count: 2
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Parameter \#1 \$array of function sort contains unresolvable type\.$#'
identifier: argument.unresolvableType
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Parameter \#2 \$columnName of method Doctrine\\ORM\\Mapping\\Driver\\DatabaseDriver\:\:getFieldNameForColumn\(\) expects string, string\|false given\.$#'
identifier: argument.type
count: 4
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Parameter \$indexedColumn of anonymous function has invalid type Doctrine\\DBAL\\Schema\\Index\\IndexedColumn\.$#'
identifier: class.notFound
count: 1
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Parameter \$name of anonymous function has invalid type Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName\.$#'
identifier: class.notFound
count: 5
path: src/Mapping/Driver/DatabaseDriver.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\SimplifiedXmlDriver\:\:__construct\(\) has parameter \$fileExtension with no type specified\.$#'
identifier: missingType.parameter
@@ -1483,7 +1351,7 @@ parameters:
path: src/Mapping/Driver/XmlDriver.php
-
message: '#^Parameter \#1 \$columnDef of method Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:setDiscriminatorColumn\(\) expects array\{name\: string\|null, fieldName\?\: string\|null, type\?\: string\|null, length\?\: int\|null, columnDefinition\?\: string\|null, enumType\?\: class\-string\<BackedEnum\>\|null, options\?\: array\<string, mixed\>\|null\}\|Doctrine\\ORM\\Mapping\\DiscriminatorColumnMapping\|null, array\{name\: string\|null, type\: string, length\: int, columnDefinition\: string\|null, enumType\: string\|null, options\?\: array\<int\|string, array\<int\|string, mixed\>\|bool\|string\>\} given\.$#'
message: '#^Parameter \#1 \$columnDef of method Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:setDiscriminatorColumn\(\) expects array\{name\: string\|null, fieldName\?\: string\|null, type\?\: string\|null, length\?\: int\|null, columnDefinition\?\: string\|null, enumType\?\: class\-string\<BackedEnum\>\|null, options\?\: array\<string, mixed\>\|null\}\|Doctrine\\ORM\\Mapping\\DiscriminatorColumnMapping\|null, array\{name\: string\|null, type\: string, length\: int, columnDefinition\: string\|null, enumType\: string\|null, options\?\: array\<int\|string, array\<int\|string, mixed\>\|bool\|object\|string\>\} given\.$#'
identifier: argument.type
count: 1
path: src/Mapping/Driver/XmlDriver.php
@@ -1513,7 +1381,7 @@ parameters:
path: src/Mapping/Driver/XmlDriver.php
-
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:\$table \(array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\?\: array\<string, mixed\>, quoted\?\: bool\}\) does not accept array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\: array\<int\|string, array\<int\|string, mixed\>\|bool\|string\>, quoted\?\: bool\}\.$#'
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:\$table \(array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\?\: array\<string, mixed\>, quoted\?\: bool\}\) does not accept array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\: array\<int\|string, array\<int\|string, mixed\>\|bool\|object\|string\>, quoted\?\: bool\}\.$#'
identifier: assign.propertyType
count: 1
path: src/Mapping/Driver/XmlDriver.php
@@ -1561,16 +1429,10 @@ parameters:
path: src/Mapping/JoinTableMapping.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\LegacyReflectionFields\:\:__construct\(\) has parameter \$classMetadata with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
message: '#^Strict comparison using \!\=\= between array\<string, string\> and null will always evaluate to true\.$#'
identifier: notIdentical.alwaysTrue
count: 1
path: src/Mapping/LegacyReflectionFields.php
-
message: '#^Parameter \#1 \$class of method Doctrine\\Persistence\\Mapping\\ReflectionService\:\:getAccessibleProperty\(\) expects class\-string, string given\.$#'
identifier: argument.type
count: 1
path: src/Mapping/LegacyReflectionFields.php
path: src/Mapping/ManyToManyOwningSideMapping.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\MappedSuperclass\:\:__construct\(\) has parameter \$repositoryClass with generic class Doctrine\\ORM\\EntityRepository but does not specify its types\: T$#'
@@ -1638,12 +1500,6 @@ parameters:
count: 1
path: src/Mapping/QuoteStrategy.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\ReflectionEnumProperty\:\:getValue\(\) return type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Mapping/ReflectionEnumProperty.php
-
message: '#^Method Doctrine\\ORM\\Mapping\\ToOneOwningSideMapping\:\:fromMappingArray\(\) should return static\(Doctrine\\ORM\\Mapping\\ToOneOwningSideMapping\) but returns Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\.$#'
identifier: return.type
@@ -1717,7 +1573,7 @@ parameters:
path: src/PersistentCollection.php
-
message: '#^Method Doctrine\\ORM\\PersistentCollection\:\:matching\(\) should return Doctrine\\Common\\Collections\\Collection\<TKey of \(int\|string\), T\> but returns Doctrine\\Common\\Collections\\ReadableCollection\<TKey of \(int\|string\), T\>&Doctrine\\Common\\Collections\\Selectable\<TKey of \(int\|string\), T\>\.$#'
message: '#^Method Doctrine\\ORM\\PersistentCollection\:\:matching\(\) should return Doctrine\\Common\\Collections\\Collection\<TKey of \(int\|string\), T\> but returns Doctrine\\Common\\Collections\\ReadableCollection\<TKey of \(int\|string\), T\>\.$#'
identifier: return.type
count: 1
path: src/PersistentCollection.php
@@ -1729,7 +1585,7 @@ parameters:
path: src/PersistentCollection.php
-
message: '#^Parameter \#2 \$callback of function array_walk expects callable\(object, int\)\: mixed, array\{Doctrine\\Common\\Collections\\Collection\<TKey of \(int\|string\), T\>&Doctrine\\Common\\Collections\\Selectable\<TKey of \(int\|string\), T\>, ''add''\} given\.$#'
message: '#^Parameter \#2 \$callback of function array_walk expects callable\(object, int\)\: mixed, array\{Doctrine\\Common\\Collections\\Collection\<TKey of \(int\|string\), T\>, ''add''\} given\.$#'
identifier: argument.type
count: 1
path: src/PersistentCollection.php
@@ -1854,6 +1710,12 @@ parameters:
count: 1
path: src/Persisters/Collection/ManyToManyPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Collection\\ManyToManyPersister\:\:count\(\) should return int\<0, max\> but returns int\.$#'
identifier: return.type
count: 1
path: src/Persisters/Collection/ManyToManyPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Collection\\ManyToManyPersister\:\:delete\(\) has parameter \$collection with generic class Doctrine\\ORM\\PersistentCollection but does not specify its types\: TKey, T$#'
identifier: missingType.generics
@@ -2022,6 +1884,12 @@ parameters:
count: 1
path: src/Persisters/Collection/OneToManyPersister.php
-
message: '#^Parameter \#1 \$columns of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getColumnDeclarationListSQL\(\) expects list\<array\{name\: string, type\: Doctrine\\DBAL\\Types\\Type, default\: mixed, notnull\?\: bool, autoincrement\: bool, columnDefinition\: non\-empty\-string\|null, comment\: string, charset\?\: non\-empty\-string\|null, \.\.\.\}\>, array\<string, array\{name\: string, notnull\: true, type\: Doctrine\\DBAL\\Types\\Type\}\> given\.$#'
identifier: argument.type
count: 1
path: src/Persisters/Collection/OneToManyPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\AbstractEntityInheritancePersister\:\:getSelectColumnSQL\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
@@ -2052,18 +1920,6 @@ parameters:
count: 4
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$relationToTargetKeyColumns\.$#'
identifier: property.notFound
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$sourceToTargetKeyColumns\.$#'
identifier: property.notFound
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Call to an undefined method Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:indexBy\(\)\.$#'
identifier: method.notFound
@@ -2076,18 +1932,6 @@ parameters:
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:expandCriteriaParameters\(\) should return array\{list\<mixed\>, list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|Doctrine\\DBAL\\ParameterType\:\:ASCII\|Doctrine\\DBAL\\ParameterType\:\:BINARY\|Doctrine\\DBAL\\ParameterType\:\:BOOLEAN\|Doctrine\\DBAL\\ParameterType\:\:INTEGER\|Doctrine\\DBAL\\ParameterType\:\:LARGE_OBJECT\|Doctrine\\DBAL\\ParameterType\:\:NULL\|Doctrine\\DBAL\\ParameterType\:\:STRING\|string\>\} but returns array\{array\<mixed\>, list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|Doctrine\\DBAL\\ParameterType\:\:ASCII\|Doctrine\\DBAL\\ParameterType\:\:BINARY\|Doctrine\\DBAL\\ParameterType\:\:BOOLEAN\|Doctrine\\DBAL\\ParameterType\:\:INTEGER\|Doctrine\\DBAL\\ParameterType\:\:LARGE_OBJECT\|Doctrine\\DBAL\\ParameterType\:\:NULL\|Doctrine\\DBAL\\ParameterType\:\:STRING\|string\>\}\.$#'
identifier: return.type
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:expandParameters\(\) should return array\{list\<mixed\>, list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|Doctrine\\DBAL\\ParameterType\:\:ASCII\|Doctrine\\DBAL\\ParameterType\:\:BINARY\|Doctrine\\DBAL\\ParameterType\:\:BOOLEAN\|Doctrine\\DBAL\\ParameterType\:\:INTEGER\|Doctrine\\DBAL\\ParameterType\:\:LARGE_OBJECT\|Doctrine\\DBAL\\ParameterType\:\:NULL\|Doctrine\\DBAL\\ParameterType\:\:STRING\|string\>\} but returns array\{array\<mixed\>, list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|Doctrine\\DBAL\\ParameterType\:\:ASCII\|Doctrine\\DBAL\\ParameterType\:\:BINARY\|Doctrine\\DBAL\\ParameterType\:\:BOOLEAN\|Doctrine\\DBAL\\ParameterType\:\:INTEGER\|Doctrine\\DBAL\\ParameterType\:\:LARGE_OBJECT\|Doctrine\\DBAL\\ParameterType\:\:NULL\|Doctrine\\DBAL\\ParameterType\:\:STRING\|string\>\}\.$#'
identifier: return.type
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:expandToManyParameters\(\) return type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
@@ -2124,12 +1968,6 @@ parameters:
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getIndividualValue\(\) should return list\<mixed\> but returns array\<mixed\>\.$#'
identifier: return.type
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getSelectColumnAssociationSQL\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
@@ -2142,18 +1980,6 @@ parameters:
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getTypes\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getTypes\(\) should return list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|Doctrine\\DBAL\\ParameterType\:\:ASCII\|Doctrine\\DBAL\\ParameterType\:\:BINARY\|Doctrine\\DBAL\\ParameterType\:\:BOOLEAN\|Doctrine\\DBAL\\ParameterType\:\:INTEGER\|Doctrine\\DBAL\\ParameterType\:\:LARGE_OBJECT\|Doctrine\\DBAL\\ParameterType\:\:NULL\|Doctrine\\DBAL\\ParameterType\:\:STRING\|string\> but returns list\<Doctrine\\DBAL\\ArrayParameterType\:\:ASCII\|Doctrine\\DBAL\\ArrayParameterType\:\:BINARY\|Doctrine\\DBAL\\ArrayParameterType\:\:INTEGER\|Doctrine\\DBAL\\ArrayParameterType\:\:STRING\|int\>\.$#'
identifier: return.type
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:loadCollectionFromStatement\(\) has parameter \$coll with generic class Doctrine\\ORM\\PersistentCollection but does not specify its types\: TKey, T$#'
identifier: missingType.generics
@@ -2178,12 +2004,6 @@ parameters:
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Parameter \#2 \$lockMode of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:appendLockHint\(\) expects Doctrine\\DBAL\\LockMode, Doctrine\\DBAL\\LockMode\:\:NONE\|Doctrine\\DBAL\\LockMode\:\:OPTIMISTIC\|Doctrine\\DBAL\\LockMode\:\:PESSIMISTIC_READ\|Doctrine\\DBAL\\LockMode\:\:PESSIMISTIC_WRITE\|int given\.$#'
identifier: argument.type
count: 2
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Parameter \#3 \$hints of method Doctrine\\ORM\\Internal\\Hydration\\AbstractHydrator\:\:hydrateAll\(\) expects array\<string, string\>, array\<string, Doctrine\\ORM\\PersistentCollection\|true\> given\.$#'
identifier: argument.type
@@ -2208,12 +2028,6 @@ parameters:
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Strict comparison using \=\=\= between string and null will always evaluate to false\.$#'
identifier: identical.alwaysFalse
count: 1
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '#^Method Doctrine\\ORM\\Persisters\\Entity\\CachedPersisterContext\:\:__construct\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
@@ -2262,12 +2076,6 @@ parameters:
count: 1
path: src/Persisters/Entity/JoinedSubclassPersister.php
-
message: '#^Parameter \#2 \$lockMode of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:appendLockHint\(\) expects Doctrine\\DBAL\\LockMode, Doctrine\\DBAL\\LockMode\:\:NONE\|Doctrine\\DBAL\\LockMode\:\:OPTIMISTIC\|Doctrine\\DBAL\\LockMode\:\:PESSIMISTIC_READ\|Doctrine\\DBAL\\LockMode\:\:PESSIMISTIC_WRITE\|int given\.$#'
identifier: argument.type
count: 1
path: src/Persisters/Entity/JoinedSubclassPersister.php
-
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$joinColumns\.$#'
identifier: property.notFound
@@ -2292,156 +2100,6 @@ parameters:
count: 1
path: src/Persisters/SqlValueVisitor.php
-
message: '#^Parameter \#3 \$className of static method Doctrine\\ORM\\Proxy\\Autoloader\:\:resolveFile\(\) expects class\-string, string given\.$#'
identifier: argument.type
count: 1
path: src/Proxy/Autoloader.php
-
message: '#^Parameter \#3 of closure expects class\-string, string given\.$#'
identifier: argument.type
count: 1
path: src/Proxy/Autoloader.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\DefaultProxyClassNameResolver\:\:resolveClassName\(\) should return class\-string\<T of object\> but returns class\-string\<Doctrine\\Persistence\\Proxy\<T of object\>\>\|class\-string\<T of object\>\.$#'
identifier: return.type
count: 1
path: src/Proxy/DefaultProxyClassNameResolver.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\DefaultProxyClassNameResolver\:\:resolveClassName\(\) should return class\-string\<T of object\> but returns string\.$#'
identifier: return.type
count: 1
path: src/Proxy/DefaultProxyClassNameResolver.php
-
message: '#^Access to an undefined property Doctrine\\Persistence\\Mapping\\ClassMetadata\:\:\$isEmbeddedClass\.$#'
identifier: property.notFound
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Access to an undefined property Doctrine\\Persistence\\Mapping\\ClassMetadata\:\:\$isMappedSuperclass\.$#'
identifier: property.notFound
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Call to an undefined static method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createLazyGhost\(\)\.$#'
identifier: staticMethod.notFound
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Call to function is_bool\(\) with bool will always evaluate to true\.$#'
identifier: function.alreadyNarrowedType
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Comparison operation "\<" between 0\|1\|2\|3\|4 and 0 is always false\.$#'
identifier: smaller.alwaysFalse
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Comparison operation "\>" between 0\|1\|2\|3\|4 and 4 is always false\.$#'
identifier: greater.alwaysFalse
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createLazyInitializer\(\) has Doctrine\\ORM\\EntityNotFoundException in PHPDoc @throws tag but it''s not thrown\.$#'
identifier: throws.unusedType
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createLazyInitializer\(\) has parameter \$classMetadata with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createLazyInitializer\(\) return type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:createLazyInitializer\(\) return type with generic interface Doctrine\\ORM\\Proxy\\InternalProxy does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateProxyClass\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateProxyClasses\(\) has parameter \$classes with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateSerializeImpl\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateUseLazyGhostTrait\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:loadProxyClass\(\) has parameter \$class with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:skipClass\(\) has parameter \$metadata with generic interface Doctrine\\Persistence\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Parameter \#1 \$class of method Doctrine\\ORM\\Utility\\IdentifierFlattener\:\:flattenIdentifier\(\) expects Doctrine\\ORM\\Mapping\\ClassMetadata, Doctrine\\Persistence\\Mapping\\ClassMetadata given\.$#'
identifier: argument.type
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Parameter \#1 \$filename of function filemtime expects string, string\|false given\.$#'
identifier: argument.type
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Parameter \#3 \$length of function substr expects int\|null, int\|false given\.$#'
identifier: argument.type
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Parameter \#3 \$newScope of static method Closure\:\:bind\(\) expects ''static''\|class\-string\|object\|null, string given\.$#'
identifier: argument.type
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Result of \|\| is always false\.$#'
identifier: booleanOr.alwaysFalse
count: 1
path: src/Proxy/ProxyFactory.php
-
message: '#^Method Doctrine\\ORM\\Query\:\:processParameterMappings\(\) return type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
@@ -2562,12 +2220,6 @@ parameters:
count: 1
path: src/Query/AST/Functions/SizeFunction.php
-
message: '#^Parameter \#2 \$mode of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getTrimExpression\(\) expects Doctrine\\DBAL\\Platforms\\TrimMode, Doctrine\\DBAL\\Platforms\\TrimMode\:\:BOTH\|Doctrine\\DBAL\\Platforms\\TrimMode\:\:LEADING\|Doctrine\\DBAL\\Platforms\\TrimMode\:\:TRAILING\|Doctrine\\DBAL\\Platforms\\TrimMode\:\:UNSPECIFIED\|int given\.$#'
identifier: argument.type
count: 2
path: src/Query/AST/Functions/TrimFunction.php
-
message: '#^Call to an undefined method Doctrine\\ORM\\Query\\SqlWalker\:\:walkJoinPathExpression\(\)\.$#'
identifier: method.notFound
@@ -2610,6 +2262,12 @@ parameters:
count: 1
path: src/Query/Exec/MultiTableDeleteExecutor.php
-
message: '#^Parameter \#1 \$columns of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getColumnDeclarationListSQL\(\) expects list\<array\{name\: string, type\: Doctrine\\DBAL\\Types\\Type, default\: mixed, notnull\?\: bool, autoincrement\: bool, columnDefinition\: non\-empty\-string\|null, comment\: string, charset\?\: non\-empty\-string\|null, \.\.\.\}\>, array\<string, array\{name\: string, notnull\: true, type\: Doctrine\\DBAL\\Types\\Type\}\> given\.$#'
identifier: argument.type
count: 1
path: src/Query/Exec/MultiTableDeleteExecutor.php
-
message: '#^Argument of an invalid type list\<string\>\|string supplied for foreach, only iterables are supported\.$#'
identifier: foreach.nonIterable
@@ -2623,7 +2281,7 @@ parameters:
path: src/Query/Exec/MultiTableUpdateExecutor.php
-
message: '#^Parameter \#3 \$types of method Doctrine\\DBAL\\Connection\:\:executeStatement\(\) expects array\<int\<0, max\>\|string, Doctrine\\DBAL\\ArrayParameterType\|Doctrine\\DBAL\\ParameterType\|Doctrine\\DBAL\\Types\\Type\|string\>, list\<Doctrine\\DBAL\\ArrayParameterType\|Doctrine\\DBAL\\ParameterType\|Doctrine\\DBAL\\Types\\Type\|int\|string\> given\.$#'
message: '#^Parameter \#1 \$columns of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getColumnDeclarationListSQL\(\) expects list\<array\{name\: string, type\: Doctrine\\DBAL\\Types\\Type, default\: mixed, notnull\?\: bool, autoincrement\: bool, columnDefinition\: non\-empty\-string\|null, comment\: string, charset\?\: non\-empty\-string\|null, \.\.\.\}\>, array\<string, array\{name\: string, notnull\: true, type\: Doctrine\\DBAL\\Types\\Type\}\> given\.$#'
identifier: argument.type
count: 1
path: src/Query/Exec/MultiTableUpdateExecutor.php
@@ -2646,42 +2304,12 @@ parameters:
count: 1
path: src/Query/Exec/SingleTableDeleteUpdateExecutor.php
-
message: '#^PHPDoc type array\<string\> of property Doctrine\\ORM\\Query\\Expr\\Andx\:\:\$allowedClasses is not covariant with PHPDoc type list\<class\-string\> of overridden property Doctrine\\ORM\\Query\\Expr\\Base\:\:\$allowedClasses\.$#'
identifier: property.phpDocType
count: 1
path: src/Query/Expr/Andx.php
-
message: '#^Method Doctrine\\ORM\\Query\\Expr\\Func\:\:getArguments\(\) should return list\<mixed\> but returns array\<mixed\>\.$#'
identifier: return.type
count: 1
path: src/Query/Expr/Func.php
-
message: '#^PHPDoc type array\<string\> of property Doctrine\\ORM\\Query\\Expr\\Orx\:\:\$allowedClasses is not covariant with PHPDoc type list\<class\-string\> of overridden property Doctrine\\ORM\\Query\\Expr\\Base\:\:\$allowedClasses\.$#'
identifier: property.phpDocType
count: 1
path: src/Query/Expr/Orx.php
-
message: '#^PHPDoc type array\<string\> of property Doctrine\\ORM\\Query\\Expr\\Select\:\:\$allowedClasses is not covariant with PHPDoc type list\<class\-string\> of overridden property Doctrine\\ORM\\Query\\Expr\\Base\:\:\$allowedClasses\.$#'
identifier: property.phpDocType
count: 1
path: src/Query/Expr/Select.php
-
message: '#^Property Doctrine\\ORM\\Query\\Filter\\SQLFilter\:\:\$parameters \(array\<string, array\{type\: string, value\: mixed, is_list\: bool\}\>\) does not accept non\-empty\-array\<string, array\{value\: mixed, type\: Doctrine\\DBAL\\ArrayParameterType\|Doctrine\\DBAL\\ParameterType\|int\|string, is_list\: bool\}\>\.$#'
identifier: assign.propertyType
count: 1
path: src/Query/Filter/SQLFilter.php
-
message: '#^Method Doctrine\\ORM\\Query\\ParameterTypeInferer\:\:inferType\(\) never returns int so it can be removed from the return type\.$#'
identifier: return.unusedType
count: 1
path: src/Query/ParameterTypeInferer.php
-
message: '#^@readonly property cannot have a default value\.$#'
identifier: property.readOnlyByPhpDocDefaultValue
@@ -2916,6 +2544,12 @@ parameters:
count: 2
path: src/QueryBuilder.php
-
message: '#^Parameter \#3 \$type of method Doctrine\\ORM\\QueryBuilder\:\:setParameter\(\) expects Doctrine\\DBAL\\ArrayParameterType\|Doctrine\\DBAL\\ParameterType\|string\|null, Doctrine\\DBAL\\ArrayParameterType\|Doctrine\\DBAL\\ParameterType\|int\|string\|null given\.$#'
identifier: argument.type
count: 1
path: src/QueryBuilder.php
-
message: '#^Method Doctrine\\ORM\\Repository\\DefaultRepositoryFactory\:\:createRepository\(\) return type with generic class Doctrine\\ORM\\EntityRepository does not specify its types\: T$#'
identifier: missingType.generics
@@ -2928,30 +2562,6 @@ parameters:
count: 1
path: src/Repository/DefaultRepositoryFactory.php
-
message: '#^Access to an undefined property Doctrine\\Persistence\\Mapping\\ClassMetadata\:\:\$name\.$#'
identifier: property.notFound
count: 1
path: src/Tools/Console/Command/GenerateProxiesCommand.php
-
message: '#^Parameter \#1 \$filename of function file_exists expects string, string\|false given\.$#'
identifier: argument.type
count: 1
path: src/Tools/Console/Command/GenerateProxiesCommand.php
-
message: '#^Parameter \#1 \$filename of function is_writable expects string, string\|false given\.$#'
identifier: argument.type
count: 1
path: src/Tools/Console/Command/GenerateProxiesCommand.php
-
message: '#^Parameter \#2 \$proxyDir of method Doctrine\\ORM\\Proxy\\ProxyFactory\:\:generateProxyClasses\(\) expects string\|null, string\|false given\.$#'
identifier: argument.type
count: 1
path: src/Tools/Console/Command/GenerateProxiesCommand.php
-
message: '#^Method Doctrine\\ORM\\Tools\\Console\\Command\\MappingDescribeCommand\:\:getClassMetadata\(\) return type with generic class Doctrine\\ORM\\Mapping\\ClassMetadata does not specify its types\: T$#'
identifier: missingType.generics
@@ -3108,12 +2718,6 @@ parameters:
count: 1
path: src/Tools/ResolveTargetEntityListener.php
-
message: '#^Parameter \#1 \$className of method Doctrine\\Persistence\\Mapping\\AbstractClassMetadataFactory\<Doctrine\\ORM\\Mapping\\ClassMetadata\>\:\:setMetadataFor\(\) expects class\-string, \(int\|string\) given\.$#'
identifier: argument.type
count: 1
path: src/Tools/ResolveTargetEntityListener.php
-
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$joinColumns\.$#'
identifier: property.notFound
@@ -3121,32 +2725,71 @@ parameters:
path: src/Tools/SchemaTool.php
-
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencedColumnNames\(\)\.$#'
identifier: method.notFound
message: '''
#^Call to deprecated method getColumns\(\) of class Doctrine\\DBAL\\Schema\\Index\:
Use \{@see getIndexedColumns\(\)\} instead\.$#
'''
identifier: method.deprecated
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencedTableName\(\)\.$#'
identifier: method.notFound
message: '''
#^Call to deprecated method getForeignColumns\(\) of class Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:
Use \{@see getReferencedColumnNames\(\)\} instead\.
Returns the names of the referenced table columns
the foreign key constraint is associated with\.$#
'''
identifier: method.deprecated
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:\:getReferencingColumnNames\(\)\.$#'
identifier: method.notFound
message: '''
#^Call to deprecated method getForeignTableName\(\) of class Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:
Use \{@see getReferencedTableName\(\)\} instead\.
Returns the name of the referenced table
the foreign key constraint is associated with\.$#
'''
identifier: method.deprecated
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\Index\:\:getIndexedColumns\(\)\.$#'
identifier: method.notFound
message: '''
#^Call to deprecated method getLocalColumns\(\) of class Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\:
Use \{@see getReferencingColumnNames\(\)\} instead\.$#
'''
identifier: method.deprecated
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Call to an undefined method Doctrine\\DBAL\\Schema\\Table\:\:dropForeignKey\(\)\.$#'
identifier: method.notFound
message: '''
#^Call to deprecated method getPrimaryKey\(\) of class Doctrine\\DBAL\\Schema\\Table\:
Use \{@see getPrimaryKeyConstraint\(\)\} instead\.$#
'''
identifier: method.deprecated
count: 1
path: src/Tools/SchemaTool.php
-
message: '''
#^Call to deprecated method removeForeignKey\(\) of class Doctrine\\DBAL\\Schema\\Table\:
Use \{@link dropForeignKey\(\)\} instead\.$#
'''
identifier: method.deprecated
count: 1
path: src/Tools/SchemaTool.php
-
message: '''
#^Call to deprecated method setPrimaryKey\(\) of class Doctrine\\DBAL\\Schema\\Table\:
Use \{@see addPrimaryKeyConstraint\(\)\} instead\.$#
'''
identifier: method.deprecated
count: 1
path: src/Tools/SchemaTool.php
@@ -3157,32 +2800,14 @@ parameters:
path: src/Tools/SchemaTool.php
-
message: '#^Call to method getColumnName\(\) on an unknown class Doctrine\\DBAL\\Schema\\Index\\IndexedColumn\.$#'
identifier: class.notFound
message: '#^Call to function method_exists\(\) with ''Doctrine\\\\DBAL\\\\Schema\\\\Index'' and ''getIndexedColumns'' will always evaluate to true\.$#'
identifier: function.alreadyNarrowedType
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Call to method getColumnNames\(\) on an unknown class Doctrine\\DBAL\\Schema\\PrimaryKeyConstraint\.$#'
identifier: class.notFound
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Call to method toString\(\) on an unknown class Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName\.$#'
identifier: class.notFound
count: 3
path: src/Tools/SchemaTool.php
-
message: '#^Class Doctrine\\DBAL\\Schema\\PrimaryKeyConstraint not found\.$#'
identifier: class.notFound
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Method Doctrine\\DBAL\\Schema\\AbstractSchemaManager\<Doctrine\\DBAL\\Platforms\\AbstractPlatform\>\:\:createComparator\(\) invoked with 1 parameter, 0 required\.$#'
identifier: arguments.count
message: '#^Call to function method_exists\(\) with Doctrine\\DBAL\\Schema\\Table and ''getPrimaryKeyConstr…'' will always evaluate to true\.$#'
identifier: function.alreadyNarrowedType
count: 1
path: src/Tools/SchemaTool.php
@@ -3228,6 +2853,12 @@ parameters:
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Method Doctrine\\ORM\\Tools\\SchemaTool\:\:getAssetName\(\) has parameter \$asset with generic class Doctrine\\DBAL\\Schema\\AbstractAsset but does not specify its types\: N$#'
identifier: missingType.generics
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Method Doctrine\\ORM\\Tools\\SchemaTool\:\:getCreateSchemaSql\(\) has parameter \$classes with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
@@ -3289,15 +2920,45 @@ parameters:
path: src/Tools/SchemaTool.php
-
message: '#^Parameter \$indexedColumn of anonymous function has invalid type Doctrine\\DBAL\\Schema\\Index\\IndexedColumn\.$#'
identifier: class.notFound
message: '#^Parameter \#1 \$columnNames of method Doctrine\\DBAL\\Schema\\Table\:\:addIndex\(\) expects non\-empty\-list\<string\>, list\<string\> given\.$#'
identifier: argument.type
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Parameter \$name of anonymous function has invalid type Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName\.$#'
identifier: class.notFound
count: 3
message: '#^Parameter \#1 \$columnNames of method Doctrine\\DBAL\\Schema\\Table\:\:addUniqueIndex\(\) expects non\-empty\-list\<string\>, array\<string\> given\.$#'
identifier: argument.type
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Parameter \#2 \$columns of class Doctrine\\DBAL\\Schema\\Index constructor expects non\-empty\-list\<string\>, list\<string\> given\.$#'
identifier: argument.type
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Parameter \#2 \$localColumnNames of method Doctrine\\DBAL\\Schema\\Table\:\:addForeignKeyConstraint\(\) expects non\-empty\-list\<string\>, list\<string\> given\.$#'
identifier: argument.type
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Parameter \#2 \$primaryKeyColumns of method Doctrine\\ORM\\Tools\\SchemaTool\:\:addPrimaryKeyConstraint\(\) expects non\-empty\-array\<non\-empty\-string\>, list\<string\> given\.$#'
identifier: argument.type
count: 2
path: src/Tools/SchemaTool.php
-
message: '#^Parameter \#2 \$primaryKeyColumns of method Doctrine\\ORM\\Tools\\SchemaTool\:\:addPrimaryKeyConstraint\(\) expects non\-empty\-array\<non\-empty\-string\>, non\-empty\-list\<string\> given\.$#'
identifier: argument.type
count: 1
path: src/Tools/SchemaTool.php
-
message: '#^Parameter \#3 \$foreignColumnNames of method Doctrine\\DBAL\\Schema\\Table\:\:addForeignKeyConstraint\(\) expects non\-empty\-list\<string\>, list\<string\> given\.$#'
identifier: argument.type
count: 1
path: src/Tools/SchemaTool.php
-
@@ -3366,6 +3027,12 @@ parameters:
count: 1
path: src/UnitOfWork.php
-
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\AssociationMapping\:\:\$joinColumns\.$#'
identifier: property.notFound
count: 1
path: src/UnitOfWork.php
-
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$inversedBy\.$#'
identifier: property.notFound
@@ -3381,7 +3048,7 @@ parameters:
-
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$mappedBy\.$#'
identifier: property.notFound
count: 1
count: 3
path: src/UnitOfWork.php
-
@@ -3450,12 +3117,6 @@ parameters:
count: 1
path: src/UnitOfWork.php
-
message: '#^PHPDoc tag @phpstan\-assert\-if\-true for \$obj contains generic interface Doctrine\\ORM\\Proxy\\InternalProxy but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/UnitOfWork.php
-
message: '#^Parameter \#2 \$assoc of method Doctrine\\ORM\\PersistentCollection\<\(int\|string\),mixed\>\:\:setOwner\(\) expects Doctrine\\ORM\\Mapping\\AssociationMapping&Doctrine\\ORM\\Mapping\\ToManyAssociationMapping, Doctrine\\ORM\\Mapping\\ManyToManyInverseSideMapping\|Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToManyAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneInverseSideMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping given\.$#'
identifier: argument.type
@@ -3474,12 +3135,6 @@ parameters:
count: 2
path: src/UnitOfWork.php
-
message: '#^Parameter \#3 \$collection of class Doctrine\\ORM\\PersistentCollection constructor expects Doctrine\\Common\\Collections\\Collection\<\(int\|string\), mixed\>&Doctrine\\Common\\Collections\\Selectable\<\(int\|string\), mixed\>, Doctrine\\Common\\Collections\\Collection given\.$#'
identifier: argument.type
count: 1
path: src/UnitOfWork.php
-
message: '#^Parameter \#5 \$invoke of method Doctrine\\ORM\\Event\\ListenersInvoker\:\:invoke\(\) expects int\<0, 7\>, int\<min, \-1\>\|int\<1, max\> given\.$#'
identifier: argument.type
@@ -3558,6 +3213,18 @@ parameters:
count: 1
path: src/Utility/PersisterHelper.php
-
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$relationToTargetKeyColumns\.$#'
identifier: property.notFound
count: 1
path: src/Utility/PersisterHelper.php
-
message: '#^Access to an undefined property Doctrine\\ORM\\Mapping\\ManyToManyOwningSideMapping\|Doctrine\\ORM\\Mapping\\ManyToOneAssociationMapping\|Doctrine\\ORM\\Mapping\\OneToOneOwningSideMapping\:\:\$sourceToTargetKeyColumns\.$#'
identifier: property.notFound
count: 1
path: src/Utility/PersisterHelper.php
-
message: '#^Method Doctrine\\ORM\\Utility\\PersisterHelper\:\:getTypeOfColumn\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
@@ -3569,3 +3236,9 @@ parameters:
identifier: missingType.generics
count: 1
path: src/Utility/PersisterHelper.php
-
message: '#^Method Doctrine\\ORM\\Utility\\PersisterHelper\:\:inferParameterTypes\(\) has parameter \$class with generic class Doctrine\\ORM\\Mapping\\ClassMetadata but does not specify its types\: T$#'
identifier: missingType.generics
count: 1
path: src/Utility/PersisterHelper.php

View File

@@ -1,89 +0,0 @@
includes:
- phpstan-baseline.neon
- phpstan-params.neon
parameters:
reportUnmatchedIgnoredErrors: false # Some errors in the baseline only apply to DBAL 4
ignoreErrors:
# Symfony cache supports passing a key prefix to the clear method.
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
# We can be certain that those values are not matched.
-
message: '~^Match expression does not handle remaining values:~'
path: src/Persisters/Entity/BasicEntityPersister.php
# DBAL 4 compatibility
-
message: '~^Method Doctrine\\ORM\\Query\\AST\\Functions\\TrimFunction::getTrimMode\(\) never returns .* so it can be removed from the return type\.$~'
path: src/Query/AST/Functions/TrimFunction.php
-
message: '~.*getTrimExpression.*expects int.*~'
path: src/Query/AST/Functions/TrimFunction.php
-
message: '~^Call to static method unquoted\(\) on an unknown class Doctrine\\DBAL\\Schema\\Name\\Identifier\.$~'
path: src/Tools/SchemaTool.php
-
message: '~^Instantiated class Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName not found\.$~'
path: src/Tools/SchemaTool.php
-
message: '~^Call to an undefined method Doctrine\\DBAL\\Schema\\Table::addPrimaryKeyConstraint\(\)\.$~'
path: src/Tools/SchemaTool.php
- '~^Class Doctrine\\DBAL\\Platforms\\SQLitePlatform not found\.$~'
# To be removed in 4.0
-
message: '#Negated boolean expression is always false\.#'
paths:
- src/Mapping/Driver/AttributeDriver.php
-
message: '~^Call to deprecated method getEventManager\(\) of class Doctrine\\DBAL\\Connection\.$~'
path: src/EntityManager.php
-
message: '~deprecated class Doctrine\\DBAL\\Tools\\Console\\Command\\ReservedWordsCommand\:~'
path: src/Tools/Console/ConsoleRunner.php
# Compatibility with Persistence 3
-
message: '#Expression on left side of \?\? is not nullable.#'
path: src/Mapping/Driver/AttributeDriver.php
-
message: '~^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getArrayBindingType\(\) never returns .* so it can be removed from the return type\.$~'
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '~getTypes.*should return~'
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '~.*appendLockHint.*expects.*LockMode given~'
paths:
- src/Persisters/Entity/BasicEntityPersister.php
- src/Persisters/Entity/JoinedSubclassPersister.php
-
message: '~.*executeStatement.*expects~'
path: src/Query/Exec/MultiTableUpdateExecutor.php
-
message: '~method_exists.*getEventManager~'
path: src/EntityManager.php
-
message: '~method_exists.*getIdentitySequence~'
path: src/Mapping/ClassMetadataFactory.php
-
message: '~expand(Criteria)?Parameters.*should return array~'
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '~inferType.*never returns~'
path: src/Query/ParameterTypeInferer.php

View File

@@ -3,6 +3,8 @@ includes:
- phpstan-params.neon
parameters:
checkMissingOverrideMethodAttribute: true
ignoreErrors:
# Symfony cache supports passing a key prefix to the clear method.
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
@@ -10,55 +12,4 @@ parameters:
# We can be certain that those values are not matched.
-
message: '~^Match expression does not handle remaining values:~'
path: src/Persisters/Entity/BasicEntityPersister.php
# DBAL 4 compatibility
-
message: '~^Method Doctrine\\ORM\\Query\\AST\\Functions\\TrimFunction::getTrimMode\(\) never returns .* so it can be removed from the return type\.$~'
path: src/Query/AST/Functions/TrimFunction.php
-
message: '~^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getArrayBindingType\(\) never returns .* so it can be removed from the return type\.$~'
path: src/Persisters/Entity/BasicEntityPersister.php
-
message: '~^Call to static method unquoted\(\) on an unknown class Doctrine\\DBAL\\Schema\\Name\\Identifier\.$~'
path: src/Tools/SchemaTool.php
-
message: '~^Instantiated class Doctrine\\DBAL\\Schema\\Name\\UnqualifiedName not found\.$~'
path: src/Tools/SchemaTool.php
-
message: '~^Call to an undefined method Doctrine\\DBAL\\Schema\\Table::addPrimaryKeyConstraint\(\)\.$~'
path: src/Tools/SchemaTool.php
# Compatibility with DBAL 3
# See https://github.com/doctrine/dbal/pull/3480
-
message: '~^Result of method Doctrine\\DBAL\\Connection::commit\(\) \(void\) is used\.$~'
path: src/UnitOfWork.php
-
message: '~^Strict comparison using === between null and false will always evaluate to false\.$~'
path: src/UnitOfWork.php
-
message: '~^Variable \$e on left side of \?\? always exists and is not nullable\.$~'
path: src/UnitOfWork.php
-
message: '~^Parameter #2 \$command of static method Doctrine\\ORM\\Tools\\Console\\ConsoleRunner::addCommandToApplication\(\) expects Symfony\\Component\\Console\\Command\\Command, Doctrine\\DBAL\\Tools\\Console\\Command\\ReservedWordsCommand given\.$~'
path: src/Tools/Console/ConsoleRunner.php
-
message: '~Strict comparison using \=\=\= between callable\(\)\: mixed and null will always evaluate to false\.~'
path: src/Tools/SchemaTool.php
# To be removed in 4.0
-
message: '#Negated boolean expression is always false\.#'
paths:
- src/Mapping/Driver/AttributeDriver.php
# Compatibility with Persistence 3
-
message: '#Expression on left side of \?\? is not nullable.#'
path: src/Mapping/Driver/AttributeDriver.php
path: src/Utility/PersisterHelper.php

View File

@@ -1,21 +0,0 @@
#!/bin/bash
# This script is a small convenience wrapper for running the doctrine testsuite against a large bunch of databases.
# Just create the phpunit.xmls as described in the array below and configure the specific files <php /> section
# to connect to that database. Just omit a file if you don't have that database and the tests will be skipped.
configs[1]="mysql.phpunit.xml"
configs[2]='postgres.phpunit.xml'
configs[3]='sqlite.phpunit.xml'
configs[4]='oracle.phpunit.xml'
configs[5]='db2.phpunit.xml'
configs[6]='pdo-ibm.phpunit.xml'
configs[7]='sqlsrv.phpunit.xml'
for i in "${configs[@]}"; do
if [ -f "$i" ];
then
echo "RUNNING TESTS WITH CONFIG $i"
phpunit -c "$i" "$@"
fi;
done

View File

@@ -16,9 +16,7 @@ use Doctrine\ORM\Cache\QueryCacheKey;
use Doctrine\ORM\Cache\TimestampCacheKey;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\Mapping\MappingException;
use LogicException;
@@ -52,32 +50,32 @@ abstract class AbstractQuery
/**
* Hydrates an object graph. This is the default behavior.
*/
public const HYDRATE_OBJECT = 1;
final public const int HYDRATE_OBJECT = 1;
/**
* Hydrates an array graph.
*/
public const HYDRATE_ARRAY = 2;
final public const int HYDRATE_ARRAY = 2;
/**
* Hydrates a flat, rectangular result set with scalar values.
*/
public const HYDRATE_SCALAR = 3;
final public const int HYDRATE_SCALAR = 3;
/**
* Hydrates a single scalar value.
*/
public const HYDRATE_SINGLE_SCALAR = 4;
final public const int HYDRATE_SINGLE_SCALAR = 4;
/**
* Very simple object hydrator (optimized for performance).
*/
public const HYDRATE_SIMPLEOBJECT = 5;
final public const int HYDRATE_SIMPLEOBJECT = 5;
/**
* Hydrates scalar column value.
*/
public const HYDRATE_SCALAR_COLUMN = 6;
final public const int HYDRATE_SCALAR_COLUMN = 6;
/**
* The parameter map of this query.
@@ -321,16 +319,16 @@ abstract class AbstractQuery
/**
* Sets a query parameter.
*
* @param string|int $key The parameter position or name.
* @param mixed $value The parameter value.
* @param ParameterType|ArrayParameterType|string|int|null $type The parameter type. If specified, the given value
* will be run through the type conversion of this
* type. This is usually not needed for strings and
* numeric types.
* @param string|int $key The parameter position or name.
* @param mixed $value The parameter value.
* @param ParameterType|ArrayParameterType|string|null $type The parameter type. If specified, the given value
* will be run through the type conversion of this
* type. This is usually not needed for strings and
* numeric types.
*
* @return $this
*/
public function setParameter(string|int $key, mixed $value, ParameterType|ArrayParameterType|string|int|null $type = null): static
public function setParameter(string|int $key, mixed $value, ParameterType|ArrayParameterType|string|null $type = null): static
{
$existingParameter = $this->getParameter($key);
@@ -379,7 +377,7 @@ abstract class AbstractQuery
}
try {
$class = DefaultProxyClassNameResolver::getClass($value);
$class = $value::class;
$value = $this->em->getUnitOfWork()->getSingleIdentifierValue($value);
if ($value === null) {
@@ -865,10 +863,6 @@ abstract class AbstractQuery
throw new LogicException('Uninitialized result set mapping.');
}
if ($rsm->isMixed && count($rsm->scalarMappings) > 0) {
throw QueryException::iterateWithMixedResultNotAllowed();
}
$stmt = $this->_doExecute();
return $this->em->newHydrator($this->hydrationMode)->toIterable($stmt, $rsm, $this->hints);
@@ -1070,7 +1064,7 @@ abstract class AbstractQuery
}
/**
* Executes the query and returns a the resulting Statement object.
* Executes the query and returns the resulting Statement object.
*
* @return Result|int The executed database statement that holds
* the results, or an integer indicating how

View File

@@ -12,31 +12,31 @@ use Doctrine\ORM\Cache\Region;
*/
interface Cache
{
public const DEFAULT_QUERY_REGION_NAME = 'query_cache_region';
final public const string DEFAULT_QUERY_REGION_NAME = 'query_cache_region';
public const DEFAULT_TIMESTAMP_REGION_NAME = 'timestamp_cache_region';
final public const string DEFAULT_TIMESTAMP_REGION_NAME = 'timestamp_cache_region';
/**
* May read items from the cache, but will not add items.
*/
public const MODE_GET = 1;
final public const int MODE_GET = 1;
/**
* Will never read items from the cache,
* but will add items to the cache as it reads them from the database.
*/
public const MODE_PUT = 2;
final public const int MODE_PUT = 2;
/**
* May read items from the cache, and add items to the cache.
*/
public const MODE_NORMAL = 3;
final public const int MODE_NORMAL = 3;
/**
* The query will never read items from the cache,
* but will refresh items to the cache as it reads them from the database.
*/
public const MODE_REFRESH = 4;
final public const int MODE_REFRESH = 4;
public function getEntityCacheRegion(string $className): Region|null;

View File

@@ -9,8 +9,8 @@ use Doctrine\ORM\Cache\Persister\CachedPersister;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMInvalidArgumentException;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\UnitOfWork;
use Override;
use function is_array;
use function is_object;
@@ -40,6 +40,7 @@ class DefaultCache implements Cache
->getCacheFactory();
}
#[Override]
public function getEntityCacheRegion(string $className): Region|null
{
$metadata = $this->em->getClassMetadata($className);
@@ -52,6 +53,7 @@ class DefaultCache implements Cache
return $persister->getCacheRegion();
}
#[Override]
public function getCollectionCacheRegion(string $className, string $association): Region|null
{
$metadata = $this->em->getClassMetadata($className);
@@ -64,6 +66,7 @@ class DefaultCache implements Cache
return $persister->getCacheRegion();
}
#[Override]
public function containsEntity(string $className, mixed $identifier): bool
{
$metadata = $this->em->getClassMetadata($className);
@@ -76,6 +79,7 @@ class DefaultCache implements Cache
return $persister->getCacheRegion()->contains($this->buildEntityCacheKey($metadata, $identifier));
}
#[Override]
public function evictEntity(string $className, mixed $identifier): void
{
$metadata = $this->em->getClassMetadata($className);
@@ -88,6 +92,7 @@ class DefaultCache implements Cache
$persister->getCacheRegion()->evict($this->buildEntityCacheKey($metadata, $identifier));
}
#[Override]
public function evictEntityRegion(string $className): void
{
$metadata = $this->em->getClassMetadata($className);
@@ -100,6 +105,7 @@ class DefaultCache implements Cache
$persister->getCacheRegion()->evictAll();
}
#[Override]
public function evictEntityRegions(): void
{
$metadatas = $this->em->getMetadataFactory()->getAllMetadata();
@@ -115,6 +121,7 @@ class DefaultCache implements Cache
}
}
#[Override]
public function containsCollection(string $className, string $association, mixed $ownerIdentifier): bool
{
$metadata = $this->em->getClassMetadata($className);
@@ -127,6 +134,7 @@ class DefaultCache implements Cache
return $persister->getCacheRegion()->contains($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier));
}
#[Override]
public function evictCollection(string $className, string $association, mixed $ownerIdentifier): void
{
$metadata = $this->em->getClassMetadata($className);
@@ -139,6 +147,7 @@ class DefaultCache implements Cache
$persister->getCacheRegion()->evict($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier));
}
#[Override]
public function evictCollectionRegion(string $className, string $association): void
{
$metadata = $this->em->getClassMetadata($className);
@@ -151,6 +160,7 @@ class DefaultCache implements Cache
$persister->getCacheRegion()->evictAll();
}
#[Override]
public function evictCollectionRegions(): void
{
$metadatas = $this->em->getMetadataFactory()->getAllMetadata();
@@ -172,11 +182,13 @@ class DefaultCache implements Cache
}
}
#[Override]
public function containsQuery(string $regionName): bool
{
return isset($this->queryCaches[$regionName]);
}
#[Override]
public function evictQueryRegion(string|null $regionName = null): void
{
if ($regionName === null && $this->defaultQueryCache !== null) {
@@ -190,6 +202,7 @@ class DefaultCache implements Cache
}
}
#[Override]
public function evictQueryRegions(): void
{
$this->getQueryCache()->clear();
@@ -199,6 +212,7 @@ class DefaultCache implements Cache
}
}
#[Override]
public function getQueryCache(string|null $regionName = null): QueryCache
{
if ($regionName === null) {
@@ -233,7 +247,7 @@ class DefaultCache implements Cache
private function toIdentifierArray(ClassMetadata $metadata, mixed $identifier): array
{
if (is_object($identifier)) {
$class = DefaultProxyClassNameResolver::getClass($identifier);
$class = $identifier::class;
if ($this->em->getMetadataFactory()->hasMetadataFor($class)) {
$identifier = $this->uow->getSingleIdentifierValue($identifier)
?? throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($class);

View File

@@ -23,6 +23,7 @@ use Doctrine\ORM\Persisters\Collection\CollectionPersister;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use InvalidArgumentException;
use LogicException;
use Override;
use Psr\Cache\CacheItemPoolInterface;
use function assert;
@@ -63,6 +64,7 @@ class DefaultCacheFactory implements CacheFactory
$this->timestampRegion = $region;
}
#[Override]
public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata): CachedEntityPersister
{
assert($metadata->cache !== null);
@@ -88,6 +90,7 @@ class DefaultCacheFactory implements CacheFactory
throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage));
}
#[Override]
public function buildCachedCollectionPersister(
EntityManagerInterface $em,
CollectionPersister $persister,
@@ -116,6 +119,7 @@ class DefaultCacheFactory implements CacheFactory
throw new InvalidArgumentException(sprintf('Unrecognized access strategy type [%s]', $usage));
}
#[Override]
public function buildQueryCache(EntityManagerInterface $em, string|null $regionName = null): QueryCache
{
return new DefaultQueryCache(
@@ -129,11 +133,13 @@ class DefaultCacheFactory implements CacheFactory
);
}
#[Override]
public function buildCollectionHydrator(EntityManagerInterface $em, AssociationMapping $mapping): CollectionHydrator
{
return new DefaultCollectionHydrator($em);
}
#[Override]
public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata): EntityHydrator
{
return new DefaultEntityHydrator($em);
@@ -142,6 +148,7 @@ class DefaultCacheFactory implements CacheFactory
/**
* {@inheritDoc}
*/
#[Override]
public function getRegion(array $cache): Region
{
if (isset($this->regions[$cache['region']])) {
@@ -170,6 +177,7 @@ class DefaultCacheFactory implements CacheFactory
return $this->regions[$cache['region']] = $region;
}
#[Override]
public function getTimestampRegion(): TimestampRegion
{
if ($this->timestampRegion === null) {
@@ -182,6 +190,7 @@ class DefaultCacheFactory implements CacheFactory
return $this->timestampRegion;
}
#[Override]
public function createCache(EntityManagerInterface $entityManager): Cache
{
return new DefaultCache($entityManager);

View File

@@ -11,6 +11,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use Override;
use function assert;
@@ -30,6 +31,7 @@ class DefaultCollectionHydrator implements CollectionHydrator
$this->uow = $em->getUnitOfWork();
}
#[Override]
public function buildCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, array|Collection $collection): CollectionCacheEntry
{
$data = [];
@@ -41,6 +43,7 @@ class DefaultCollectionHydrator implements CollectionHydrator
return new CollectionCacheEntry($data);
}
#[Override]
public function loadCacheEntry(ClassMetadata $metadata, CollectionCacheKey $key, CollectionCacheEntry $entry, PersistentCollection $collection): array|null
{
$assoc = $metadata->associationMappings[$key->association];

View File

@@ -6,10 +6,10 @@ namespace Doctrine\ORM\Cache;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use Doctrine\ORM\Utility\IdentifierFlattener;
use Override;
use function assert;
use function is_array;
@@ -34,6 +34,7 @@ class DefaultEntityHydrator implements EntityHydrator
$this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory());
}
#[Override]
public function buildCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, object $entity): EntityCacheEntry
{
$data = $this->uow->getOriginalEntityData($entity);
@@ -97,7 +98,7 @@ class DefaultEntityHydrator implements EntityHydrator
}
if (! isset($assoc->id)) {
$targetClass = DefaultProxyClassNameResolver::getClass($data[$name]);
$targetClass = $data[$name]::class;
$targetId = $this->uow->getEntityIdentifier($data[$name]);
$data[$name] = new AssociationCacheEntry($targetClass, $targetId);
@@ -125,6 +126,7 @@ class DefaultEntityHydrator implements EntityHydrator
return new EntityCacheEntry($metadata->name, $data);
}
#[Override]
public function loadCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, EntityCacheEntry $entry, object|null $entity = null): object|null
{
$data = $entry->data;

View File

@@ -18,6 +18,7 @@ use Doctrine\ORM\Query;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\UnitOfWork;
use Override;
use function array_map;
use function array_shift;
@@ -54,6 +55,7 @@ class DefaultQueryCache implements QueryCache
/**
* {@inheritDoc}
*/
#[Override]
public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = []): array|null
{
if (! ($key->cacheMode & Cache::MODE_GET)) {
@@ -197,6 +199,7 @@ class DefaultQueryCache implements QueryCache
/**
* {@inheritDoc}
*/
#[Override]
public function put(QueryCacheKey $key, ResultSetMapping $rsm, mixed $result, array $hints = []): bool
{
if ($rsm->scalarMappings) {
@@ -406,11 +409,13 @@ class DefaultQueryCache implements QueryCache
return $values;
}
#[Override]
public function clear(): bool
{
return $this->region->evictAll();
}
#[Override]
public function getRegion(): Region
{
return $this->region;

View File

@@ -7,6 +7,7 @@ namespace Doctrine\ORM\Cache\Logging;
use Doctrine\ORM\Cache\CollectionCacheKey;
use Doctrine\ORM\Cache\EntityCacheKey;
use Doctrine\ORM\Cache\QueryCacheKey;
use Override;
class CacheLoggerChain implements CacheLogger
{
@@ -29,6 +30,7 @@ class CacheLoggerChain implements CacheLogger
return $this->loggers;
}
#[Override]
public function collectionCacheHit(string $regionName, CollectionCacheKey $key): void
{
foreach ($this->loggers as $logger) {
@@ -36,6 +38,7 @@ class CacheLoggerChain implements CacheLogger
}
}
#[Override]
public function collectionCacheMiss(string $regionName, CollectionCacheKey $key): void
{
foreach ($this->loggers as $logger) {
@@ -43,6 +46,7 @@ class CacheLoggerChain implements CacheLogger
}
}
#[Override]
public function collectionCachePut(string $regionName, CollectionCacheKey $key): void
{
foreach ($this->loggers as $logger) {
@@ -50,6 +54,7 @@ class CacheLoggerChain implements CacheLogger
}
}
#[Override]
public function entityCacheHit(string $regionName, EntityCacheKey $key): void
{
foreach ($this->loggers as $logger) {
@@ -57,6 +62,7 @@ class CacheLoggerChain implements CacheLogger
}
}
#[Override]
public function entityCacheMiss(string $regionName, EntityCacheKey $key): void
{
foreach ($this->loggers as $logger) {
@@ -64,6 +70,7 @@ class CacheLoggerChain implements CacheLogger
}
}
#[Override]
public function entityCachePut(string $regionName, EntityCacheKey $key): void
{
foreach ($this->loggers as $logger) {
@@ -71,6 +78,7 @@ class CacheLoggerChain implements CacheLogger
}
}
#[Override]
public function queryCacheHit(string $regionName, QueryCacheKey $key): void
{
foreach ($this->loggers as $logger) {
@@ -78,6 +86,7 @@ class CacheLoggerChain implements CacheLogger
}
}
#[Override]
public function queryCacheMiss(string $regionName, QueryCacheKey $key): void
{
foreach ($this->loggers as $logger) {
@@ -85,6 +94,7 @@ class CacheLoggerChain implements CacheLogger
}
}
#[Override]
public function queryCachePut(string $regionName, QueryCacheKey $key): void
{
foreach ($this->loggers as $logger) {

View File

@@ -7,6 +7,7 @@ namespace Doctrine\ORM\Cache\Logging;
use Doctrine\ORM\Cache\CollectionCacheKey;
use Doctrine\ORM\Cache\EntityCacheKey;
use Doctrine\ORM\Cache\QueryCacheKey;
use Override;
use function array_sum;
@@ -24,54 +25,63 @@ class StatisticsCacheLogger implements CacheLogger
/** @var array<string, int> */
private array $cachePutCountMap = [];
#[Override]
public function collectionCacheMiss(string $regionName, CollectionCacheKey $key): void
{
$this->cacheMissCountMap[$regionName]
= ($this->cacheMissCountMap[$regionName] ?? 0) + 1;
}
#[Override]
public function collectionCacheHit(string $regionName, CollectionCacheKey $key): void
{
$this->cacheHitCountMap[$regionName]
= ($this->cacheHitCountMap[$regionName] ?? 0) + 1;
}
#[Override]
public function collectionCachePut(string $regionName, CollectionCacheKey $key): void
{
$this->cachePutCountMap[$regionName]
= ($this->cachePutCountMap[$regionName] ?? 0) + 1;
}
#[Override]
public function entityCacheMiss(string $regionName, EntityCacheKey $key): void
{
$this->cacheMissCountMap[$regionName]
= ($this->cacheMissCountMap[$regionName] ?? 0) + 1;
}
#[Override]
public function entityCacheHit(string $regionName, EntityCacheKey $key): void
{
$this->cacheHitCountMap[$regionName]
= ($this->cacheHitCountMap[$regionName] ?? 0) + 1;
}
#[Override]
public function entityCachePut(string $regionName, EntityCacheKey $key): void
{
$this->cachePutCountMap[$regionName]
= ($this->cachePutCountMap[$regionName] ?? 0) + 1;
}
#[Override]
public function queryCacheHit(string $regionName, QueryCacheKey $key): void
{
$this->cacheHitCountMap[$regionName]
= ($this->cacheHitCountMap[$regionName] ?? 0) + 1;
}
#[Override]
public function queryCacheMiss(string $regionName, QueryCacheKey $key): void
{
$this->cacheMissCountMap[$regionName]
= ($this->cacheMissCountMap[$regionName] ?? 0) + 1;
}
#[Override]
public function queryCachePut(string $regionName, QueryCacheKey $key): void
{
$this->cachePutCountMap[$regionName]

View File

@@ -17,9 +17,9 @@ use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\Query\FilterCollection;
use Doctrine\ORM\UnitOfWork;
use Override;
use function array_values;
use function assert;
@@ -63,21 +63,25 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
$this->targetEntity = $em->getClassMetadata($association->targetEntity);
}
#[Override]
public function getCacheRegion(): Region
{
return $this->region;
}
#[Override]
public function getSourceEntityMetadata(): ClassMetadata
{
return $this->sourceEntity;
}
#[Override]
public function getTargetEntityMetadata(): ClassMetadata
{
return $this->targetEntity;
}
#[Override]
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key): array|null
{
$cache = $this->region->get($key);
@@ -89,6 +93,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
return $this->hydrator->loadCacheEntry($this->sourceEntity, $key, $cache, $collection);
}
#[Override]
public function storeCollectionCache(CollectionCacheKey $key, Collection|array $elements): void
{
$associationMapping = $this->sourceEntity->associationMappings[$key->association];
@@ -111,7 +116,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
}
$class = $this->targetEntity;
$className = DefaultProxyClassNameResolver::getClass($elements[$index]);
$className = $elements[$index]::class;
if ($className !== $this->targetEntity->name) {
$class = $this->metadataFactory->getMetadataFor($className);
@@ -128,16 +133,19 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
}
}
#[Override]
public function contains(PersistentCollection $collection, object $element): bool
{
return $this->persister->contains($collection, $element);
}
#[Override]
public function containsKey(PersistentCollection $collection, mixed $key): bool
{
return $this->persister->containsKey($collection, $key);
}
#[Override]
public function count(PersistentCollection $collection): int
{
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
@@ -151,6 +159,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
return $this->persister->count($collection);
}
#[Override]
public function get(PersistentCollection $collection, mixed $index): mixed
{
return $this->persister->get($collection, $index);
@@ -159,6 +168,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
/**
* {@inheritDoc}
*/
#[Override]
public function slice(PersistentCollection $collection, int $offset, int|null $length = null): array
{
return $this->persister->slice($collection, $offset, $length);
@@ -167,6 +177,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
/**
* {@inheritDoc}
*/
#[Override]
public function loadCriteria(PersistentCollection $collection, Criteria $criteria): array
{
return $this->persister->loadCriteria($collection, $criteria);

View File

@@ -6,11 +6,13 @@ namespace Doctrine\ORM\Cache\Persister\Collection;
use Doctrine\ORM\Cache\CollectionCacheKey;
use Doctrine\ORM\PersistentCollection;
use Override;
use function spl_object_id;
class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPersister
{
#[Override]
public function afterTransactionComplete(): void
{
if (isset($this->queuedCache['update'])) {
@@ -28,11 +30,13 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
$this->queuedCache = [];
}
#[Override]
public function afterTransactionRolledBack(): void
{
$this->queuedCache = [];
}
#[Override]
public function delete(PersistentCollection $collection): void
{
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
@@ -43,6 +47,7 @@ class NonStrictReadWriteCachedCollectionPersister extends AbstractCollectionPers
$this->queuedCache['delete'][spl_object_id($collection)] = $key;
}
#[Override]
public function update(PersistentCollection $collection): void
{
$isInitialized = $collection->isInitialized();

View File

@@ -6,15 +6,16 @@ namespace Doctrine\ORM\Cache\Persister\Collection;
use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyCollection;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Override;
class ReadOnlyCachedCollectionPersister extends NonStrictReadWriteCachedCollectionPersister
{
#[Override]
public function update(PersistentCollection $collection): void
{
if ($collection->isDirty() && $collection->getSnapshot()) {
throw CannotUpdateReadOnlyCollection::fromEntityAndField(
DefaultProxyClassNameResolver::getClass($collection->getOwner()),
$collection->getOwner()::class,
$this->association->fieldName,
);
}

View File

@@ -10,6 +10,7 @@ use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
use Override;
use function spl_object_id;
@@ -24,6 +25,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
parent::__construct($persister, $region, $em, $association);
}
#[Override]
public function afterTransactionComplete(): void
{
if (isset($this->queuedCache['update'])) {
@@ -41,6 +43,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
$this->queuedCache = [];
}
#[Override]
public function afterTransactionRolledBack(): void
{
if (isset($this->queuedCache['update'])) {
@@ -58,6 +61,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
$this->queuedCache = [];
}
#[Override]
public function delete(PersistentCollection $collection): void
{
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
@@ -76,6 +80,7 @@ class ReadWriteCachedCollectionPersister extends AbstractCollectionPersister
];
}
#[Override]
public function update(PersistentCollection $collection): void
{
$isInitialized = $collection->isInitialized();

View File

@@ -23,13 +23,12 @@ use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\Query\FilterCollection;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\UnitOfWork;
use Override;
use function array_merge;
use function func_get_args;
use function serialize;
use function sha1;
@@ -77,6 +76,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
$this->timestampKey = new TimestampCacheKey($this->class->rootEntityName);
}
#[Override]
public function addInsert(object $entity): void
{
$this->persister->addInsert($entity);
@@ -85,15 +85,17 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function getInserts(): array
{
return $this->persister->getInserts();
}
#[Override]
public function getSelectSQL(
array|Criteria $criteria,
AssociationMapping|null $assoc = null,
LockMode|int|null $lockMode = null,
LockMode|null $lockMode = null,
int|null $limit = null,
int|null $offset = null,
array|null $orderBy = null,
@@ -101,21 +103,25 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $this->persister->getSelectSQL($criteria, $assoc, $lockMode, $limit, $offset, $orderBy);
}
#[Override]
public function getCountSQL(array|Criteria $criteria = []): string
{
return $this->persister->getCountSQL($criteria);
}
#[Override]
public function getInsertSQL(): string
{
return $this->persister->getInsertSQL();
}
#[Override]
public function getResultSetMapping(): ResultSetMapping
{
return $this->persister->getResultSetMapping();
}
#[Override]
public function getSelectConditionStatementSQL(
string $field,
mixed $value,
@@ -125,6 +131,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $this->persister->getSelectConditionStatementSQL($field, $value, $assoc, $comparison);
}
#[Override]
public function exists(object $entity, Criteria|null $extraConditions = null): bool
{
if ($extraConditions === null) {
@@ -138,20 +145,23 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $this->persister->exists($entity, $extraConditions);
}
#[Override]
public function getCacheRegion(): Region
{
return $this->region;
}
#[Override]
public function getEntityHydrator(): EntityHydrator
{
return $this->hydrator;
}
#[Override]
public function storeEntityCache(object $entity, EntityCacheKey $key): bool
{
$class = $this->class;
$className = DefaultProxyClassNameResolver::getClass($entity);
$className = $entity::class;
if ($className !== $this->class->name) {
$class = $this->metadataFactory->getMetadataFor($className);
@@ -225,6 +235,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function expandParameters(array $criteria): array
{
return $this->persister->expandParameters($criteria);
@@ -233,11 +244,13 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function expandCriteriaParameters(Criteria $criteria): array
{
return $this->persister->expandCriteriaParameters($criteria);
}
#[Override]
public function getClassMetadata(): ClassMetadata
{
return $this->persister->getClassMetadata();
@@ -246,6 +259,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function getManyToManyCollection(
AssociationMapping $assoc,
object $sourceEntity,
@@ -258,6 +272,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function getOneToManyCollection(
AssociationMapping $assoc,
object $sourceEntity,
@@ -267,11 +282,13 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $this->persister->getOneToManyCollection($assoc, $sourceEntity, $offset, $limit);
}
#[Override]
public function getOwningTable(string $fieldName): string
{
return $this->persister->getOwningTable($fieldName);
}
#[Override]
public function executeInserts(): void
{
// The commit order/foreign key relationships may make it necessary that multiple calls to executeInsert()
@@ -288,12 +305,13 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function load(
array $criteria,
object|null $entity = null,
AssociationMapping|null $assoc = null,
array $hints = [],
LockMode|int|null $lockMode = null,
LockMode|null $lockMode = null,
int|null $limit = null,
array|null $orderBy = null,
): object|null {
@@ -335,6 +353,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function loadAll(
array $criteria = [],
array|null $orderBy = null,
@@ -371,6 +390,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function loadById(array $identifier, object|null $entity = null): object|null
{
$cacheKey = new EntityCacheKey($this->class->rootEntityName, $identifier);
@@ -398,7 +418,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
}
$class = $this->class;
$className = DefaultProxyClassNameResolver::getClass($entity);
$className = $entity::class;
if ($className !== $this->class->name) {
$class = $this->metadataFactory->getMetadataFor($className);
@@ -420,6 +440,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $entity;
}
#[Override]
public function count(array|Criteria $criteria = []): int
{
return $this->persister->count($criteria);
@@ -428,6 +449,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function loadCriteria(Criteria $criteria): array
{
$orderBy = $criteria->orderings();
@@ -463,6 +485,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function loadManyToManyCollection(
AssociationMapping $assoc,
object $sourceEntity,
@@ -494,6 +517,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $list;
}
#[Override]
public function loadOneToManyCollection(
AssociationMapping $assoc,
object $sourceEntity,
@@ -528,6 +552,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
#[Override]
public function loadOneToOneEntity(AssociationMapping $assoc, object $sourceEntity, array $identifier = []): object|null
{
return $this->persister->loadOneToOneEntity($assoc, $sourceEntity, $identifier);
@@ -536,7 +561,8 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
public function lock(array $criteria, LockMode|int $lockMode): void
#[Override]
public function lock(array $criteria, LockMode $lockMode): void
{
$this->persister->lock($criteria, $lockMode);
}
@@ -544,16 +570,15 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritDoc}
*/
public function refresh(array $id, object $entity, LockMode|int|null $lockMode = null): void
#[Override]
public function refresh(array $id, object $entity, LockMode|null $lockMode = null): void
{
$this->persister->refresh($id, $entity, $lockMode);
}
/** @param array<string, mixed> $ownerId */
protected function buildCollectionCacheKey(AssociationMapping $association, array $ownerId, /* string $filterHash */): CollectionCacheKey
protected function buildCollectionCacheKey(AssociationMapping $association, array $ownerId, string $filterHash): CollectionCacheKey
{
$filterHash = (string) (func_get_args()[2] ?? ''); // todo: move to argument in next major release
return new CollectionCacheKey(
$this->metadataFactory->getMetadataFor($association->sourceEntity)->rootEntityName,
$association->fieldName,

View File

@@ -5,12 +5,14 @@ declare(strict_types=1);
namespace Doctrine\ORM\Cache\Persister\Entity;
use Doctrine\ORM\Cache\EntityCacheKey;
use Override;
/**
* Specific non-strict read/write cached entity persister
*/
class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
{
#[Override]
public function afterTransactionComplete(): void
{
$isChanged = false;
@@ -42,11 +44,13 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
$this->queuedCache = [];
}
#[Override]
public function afterTransactionRolledBack(): void
{
$this->queuedCache = [];
}
#[Override]
public function delete(object $entity): bool
{
$key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity));
@@ -61,6 +65,7 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
return $deleted;
}
#[Override]
public function update(object $entity): void
{
$this->persister->update($entity);

View File

@@ -5,15 +5,16 @@ declare(strict_types=1);
namespace Doctrine\ORM\Cache\Persister\Entity;
use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyEntity;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Override;
/**
* Specific read-only region entity persister
*/
class ReadOnlyCachedEntityPersister extends NonStrictReadWriteCachedEntityPersister
{
#[Override]
public function update(object $entity): void
{
throw CannotUpdateReadOnlyEntity::fromEntity(DefaultProxyClassNameResolver::getClass($entity));
throw CannotUpdateReadOnlyEntity::fromEntity($entity::class);
}
}

View File

@@ -9,6 +9,7 @@ use Doctrine\ORM\Cache\EntityCacheKey;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use Override;
/**
* Specific read-write entity persister
@@ -20,6 +21,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
parent::__construct($persister, $region, $em, $class);
}
#[Override]
public function afterTransactionComplete(): void
{
$isChanged = true;
@@ -47,6 +49,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
$this->queuedCache = [];
}
#[Override]
public function afterTransactionRolledBack(): void
{
if (isset($this->queuedCache['update'])) {
@@ -64,6 +67,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
$this->queuedCache = [];
}
#[Override]
public function delete(object $entity): bool
{
$key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity));
@@ -86,6 +90,7 @@ class ReadWriteCachedEntityPersister extends AbstractEntityPersister
return $deleted;
}
#[Override]
public function update(object $entity): void
{
$key = new EntityCacheKey($this->class->rootEntityName, $this->uow->getEntityIdentifier($entity));

View File

@@ -9,6 +9,7 @@ use Doctrine\ORM\Cache\CacheKey;
use Doctrine\ORM\Cache\CollectionCacheEntry;
use Doctrine\ORM\Cache\Lock;
use Doctrine\ORM\Cache\Region;
use Override;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Traversable;
@@ -22,8 +23,8 @@ use function strtr;
*/
class DefaultRegion implements Region
{
private const REGION_KEY_SEPARATOR = '_';
private const REGION_PREFIX = 'DC2_REGION_';
private const string REGION_KEY_SEPARATOR = '_';
private const string REGION_PREFIX = 'DC2_REGION_';
public function __construct(
private readonly string $name,
@@ -32,16 +33,19 @@ class DefaultRegion implements Region
) {
}
#[Override]
public function getName(): string
{
return $this->name;
}
#[Override]
public function contains(CacheKey $key): bool
{
return $this->cacheItemPool->hasItem($this->getCacheEntryKey($key));
}
#[Override]
public function get(CacheKey $key): CacheEntry|null
{
$item = $this->cacheItemPool->getItem($this->getCacheEntryKey($key));
@@ -54,6 +58,7 @@ class DefaultRegion implements Region
return $entry;
}
#[Override]
public function getMultiple(CollectionCacheEntry $collection): array|null
{
$keys = array_map(
@@ -83,6 +88,7 @@ class DefaultRegion implements Region
return $result;
}
#[Override]
public function put(CacheKey $key, CacheEntry $entry, Lock|null $lock = null): bool
{
$item = $this->cacheItemPool
@@ -96,11 +102,13 @@ class DefaultRegion implements Region
return $this->cacheItemPool->save($item);
}
#[Override]
public function evict(CacheKey $key): bool
{
return $this->cacheItemPool->deleteItem($this->getCacheEntryKey($key));
}
#[Override]
public function evictAll(): bool
{
return $this->cacheItemPool->clear(self::REGION_PREFIX . $this->name);

View File

@@ -11,6 +11,7 @@ use Doctrine\ORM\Cache\ConcurrentRegion;
use Doctrine\ORM\Cache\Lock;
use Doctrine\ORM\Cache\Region;
use InvalidArgumentException;
use Override;
use function array_filter;
use function array_map;
@@ -35,7 +36,7 @@ use const LOCK_EX;
*/
class FileLockRegion implements ConcurrentRegion
{
final public const LOCK_EXTENSION = 'lock';
final public const string LOCK_EXTENSION = 'lock';
/**
* @param numeric-string|int $lockLifetime
@@ -102,11 +103,13 @@ class FileLockRegion implements ConcurrentRegion
return @fileatime($filename);
}
#[Override]
public function getName(): string
{
return $this->region->getName();
}
#[Override]
public function contains(CacheKey $key): bool
{
if ($this->isLocked($key)) {
@@ -116,6 +119,7 @@ class FileLockRegion implements ConcurrentRegion
return $this->region->contains($key);
}
#[Override]
public function get(CacheKey $key): CacheEntry|null
{
if ($this->isLocked($key)) {
@@ -125,6 +129,7 @@ class FileLockRegion implements ConcurrentRegion
return $this->region->get($key);
}
#[Override]
public function getMultiple(CollectionCacheEntry $collection): array|null
{
if (array_filter(array_map($this->isLocked(...), $collection->identifiers))) {
@@ -134,6 +139,7 @@ class FileLockRegion implements ConcurrentRegion
return $this->region->getMultiple($collection);
}
#[Override]
public function put(CacheKey $key, CacheEntry $entry, Lock|null $lock = null): bool
{
if ($this->isLocked($key, $lock)) {
@@ -143,6 +149,7 @@ class FileLockRegion implements ConcurrentRegion
return $this->region->put($key, $entry);
}
#[Override]
public function evict(CacheKey $key): bool
{
if ($this->isLocked($key)) {
@@ -152,6 +159,7 @@ class FileLockRegion implements ConcurrentRegion
return $this->region->evict($key);
}
#[Override]
public function evictAll(): bool
{
// The check below is necessary because on some platforms glob returns false
@@ -165,6 +173,7 @@ class FileLockRegion implements ConcurrentRegion
return $this->region->evictAll();
}
#[Override]
public function lock(CacheKey $key): Lock|null
{
if ($this->isLocked($key)) {
@@ -183,6 +192,7 @@ class FileLockRegion implements ConcurrentRegion
return $lock;
}
#[Override]
public function unlock(CacheKey $key, Lock $lock): bool
{
if ($this->isLocked($key, $lock)) {

View File

@@ -7,12 +7,14 @@ namespace Doctrine\ORM\Cache\Region;
use Doctrine\ORM\Cache\CacheKey;
use Doctrine\ORM\Cache\TimestampCacheEntry;
use Doctrine\ORM\Cache\TimestampRegion;
use Override;
/**
* Tracks the timestamps of the most recent updates to particular keys.
*/
class UpdateTimestampCache extends DefaultRegion implements TimestampRegion
{
#[Override]
public function update(CacheKey $key): void
{
$this->put($key, new TimestampCacheEntry());

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Doctrine\ORM\Cache;
use Override;
use function microtime;
class TimestampQueryCacheValidator implements QueryCacheValidator
@@ -12,6 +14,7 @@ class TimestampQueryCacheValidator implements QueryCacheValidator
{
}
#[Override]
public function isValid(QueryCacheKey $key, QueryCacheEntry $entry): bool
{
if ($this->regionUpdated($key, $entry)) {

View File

@@ -17,21 +17,17 @@ use Doctrine\ORM\Mapping\EntityListenerResolver;
use Doctrine\ORM\Mapping\NamingStrategy;
use Doctrine\ORM\Mapping\QuoteStrategy;
use Doctrine\ORM\Mapping\TypedFieldMapper;
use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Filter\SQLFilter;
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
use Doctrine\ORM\Repository\RepositoryFactory;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use LogicException;
use Psr\Cache\CacheItemPoolInterface;
use function class_exists;
use function is_a;
use function strtolower;
use const PHP_VERSION_ID;
/**
* Configuration container for all configuration options of Doctrine.
* It combines all configuration options from DBAL & ORM.
@@ -58,58 +54,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
return $this->identityGenerationPreferences;
}
/**
* Sets the directory where Doctrine generates any necessary proxy class files.
*/
public function setProxyDir(string $dir): void
{
$this->attributes['proxyDir'] = $dir;
}
/**
* Gets the directory where Doctrine generates any necessary proxy class files.
*/
public function getProxyDir(): string|null
{
return $this->attributes['proxyDir'] ?? null;
}
/**
* Gets the strategy for automatically generating proxy classes.
*
* @return ProxyFactory::AUTOGENERATE_*
*/
public function getAutoGenerateProxyClasses(): int
{
return $this->attributes['autoGenerateProxyClasses'] ?? ProxyFactory::AUTOGENERATE_ALWAYS;
}
/**
* Sets the strategy for automatically generating proxy classes.
*
* @param bool|ProxyFactory::AUTOGENERATE_* $autoGenerate True is converted to AUTOGENERATE_ALWAYS, false to AUTOGENERATE_NEVER.
*/
public function setAutoGenerateProxyClasses(bool|int $autoGenerate): void
{
$this->attributes['autoGenerateProxyClasses'] = (int) $autoGenerate;
}
/**
* Gets the namespace where proxy classes reside.
*/
public function getProxyNamespace(): string|null
{
return $this->attributes['proxyNamespace'] ?? null;
}
/**
* Sets the namespace where proxy classes reside.
*/
public function setProxyNamespace(string $ns): void
{
$this->attributes['proxyNamespace'] = $ns;
}
/**
* Sets the cache driver implementation that is used for metadata caching.
*
@@ -595,62 +539,6 @@ class Configuration extends \Doctrine\DBAL\Configuration
$this->attributes['schemaIgnoreClasses'] = $schemaIgnoreClasses;
}
public function isNativeLazyObjectsEnabled(): bool
{
return $this->attributes['nativeLazyObjects'] ?? false;
}
public function enableNativeLazyObjects(bool $nativeLazyObjects): void
{
if (PHP_VERSION_ID < 80400) {
throw new LogicException('Lazy loading proxies require PHP 8.4 or higher.');
}
$this->attributes['nativeLazyObjects'] = $nativeLazyObjects;
}
/**
* To be deprecated in 3.1.0
*
* @return true
*/
public function isLazyGhostObjectEnabled(): bool
{
return true;
}
/** To be deprecated in 3.1.0 */
public function setLazyGhostObjectEnabled(bool $flag): void
{
if (! $flag) {
throw new LogicException(<<<'EXCEPTION'
The lazy ghost object feature cannot be disabled anymore.
Please remove the call to setLazyGhostObjectEnabled(false).
EXCEPTION);
}
}
/** To be deprecated in 3.1.0 */
public function setRejectIdCollisionInIdentityMap(bool $flag): void
{
if (! $flag) {
throw new LogicException(<<<'EXCEPTION'
Rejecting ID collisions in the identity map cannot be disabled anymore.
Please remove the call to setRejectIdCollisionInIdentityMap(false).
EXCEPTION);
}
}
/**
* To be deprecated in 3.1.0
*
* @return true
*/
public function isRejectIdCollisionInIdentityMapEnabled(): bool
{
return true;
}
public function setEagerFetchBatchSize(int $batchSize = 100): void
{
$this->attributes['fetchModeSubselectBatchSize'] = $batchSize;

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Doctrine\ORM\Decorator;
use DateTimeInterface;
use Doctrine\Common\EventManager;
use Doctrine\Common\EventManagerInterface;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\Cache;
@@ -24,6 +24,7 @@ use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\UnitOfWork;
use Doctrine\Persistence\ObjectManagerDecorator;
use Override;
/**
* Base class for EntityManager decorators
@@ -37,136 +38,163 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
$this->wrapped = $wrapped;
}
#[Override]
public function getRepository(string $className): EntityRepository
{
return $this->wrapped->getRepository($className);
}
#[Override]
public function getMetadataFactory(): ClassMetadataFactory
{
return $this->wrapped->getMetadataFactory();
}
#[Override]
public function getClassMetadata(string $className): ClassMetadata
{
return $this->wrapped->getClassMetadata($className);
}
#[Override]
public function getConnection(): Connection
{
return $this->wrapped->getConnection();
}
#[Override]
public function getExpressionBuilder(): Expr
{
return $this->wrapped->getExpressionBuilder();
}
#[Override]
public function beginTransaction(): void
{
$this->wrapped->beginTransaction();
}
#[Override]
public function wrapInTransaction(callable $func): mixed
{
return $this->wrapped->wrapInTransaction($func);
}
#[Override]
public function commit(): void
{
$this->wrapped->commit();
}
#[Override]
public function rollback(): void
{
$this->wrapped->rollback();
}
#[Override]
public function createQuery(string $dql = ''): Query
{
return $this->wrapped->createQuery($dql);
}
#[Override]
public function createNativeQuery(string $sql, ResultSetMapping $rsm): NativeQuery
{
return $this->wrapped->createNativeQuery($sql, $rsm);
}
#[Override]
public function createQueryBuilder(): QueryBuilder
{
return $this->wrapped->createQueryBuilder();
}
#[Override]
public function getReference(string $entityName, mixed $id): object|null
{
return $this->wrapped->getReference($entityName, $id);
}
#[Override]
public function close(): void
{
$this->wrapped->close();
}
public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|int|null $lockVersion = null): void
#[Override]
public function lock(object $entity, LockMode $lockMode, DateTimeInterface|int|null $lockVersion = null): void
{
$this->wrapped->lock($entity, $lockMode, $lockVersion);
}
public function find(string $className, mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null
#[Override]
public function find(string $className, mixed $id, LockMode|null $lockMode = null, int|null $lockVersion = null): object|null
{
return $this->wrapped->find($className, $id, $lockMode, $lockVersion);
}
public function refresh(object $object, LockMode|int|null $lockMode = null): void
#[Override]
public function refresh(object $object, LockMode|null $lockMode = null): void
{
$this->wrapped->refresh($object, $lockMode);
}
public function getEventManager(): EventManager
#[Override]
public function getEventManager(): EventManagerInterface
{
return $this->wrapped->getEventManager();
}
#[Override]
public function getConfiguration(): Configuration
{
return $this->wrapped->getConfiguration();
}
#[Override]
public function isOpen(): bool
{
return $this->wrapped->isOpen();
}
#[Override]
public function getUnitOfWork(): UnitOfWork
{
return $this->wrapped->getUnitOfWork();
}
#[Override]
public function newHydrator(string|int $hydrationMode): AbstractHydrator
{
return $this->wrapped->newHydrator($hydrationMode);
}
#[Override]
public function getProxyFactory(): ProxyFactory
{
return $this->wrapped->getProxyFactory();
}
#[Override]
public function getFilters(): FilterCollection
{
return $this->wrapped->getFilters();
}
#[Override]
public function isFiltersStateClean(): bool
{
return $this->wrapped->isFiltersStateClean();
}
#[Override]
public function hasFilters(): bool
{
return $this->wrapped->hasFilters();
}
#[Override]
public function getCache(): Cache|null
{
return $this->wrapped->getCache();

View File

@@ -7,6 +7,7 @@ namespace Doctrine\ORM;
use BackedEnum;
use DateTimeInterface;
use Doctrine\Common\EventManager;
use Doctrine\Common\EventManagerInterface;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\Exception\EntityManagerClosed;
@@ -18,18 +19,17 @@ use Doctrine\ORM\Exception\UnrecognizedIdentifierFields;
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\FilterCollection;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Repository\RepositoryFactory;
use Override;
use function array_keys;
use function is_array;
use function is_object;
use function ltrim;
use function method_exists;
/**
* The EntityManager is the central access point to ORM functionality.
@@ -43,7 +43,7 @@ use function method_exists;
*
* $paths = ['/path/to/entity/mapping/files'];
*
* $config = ORMSetup::createAttributeMetadataConfiguration($paths);
* $config = ORMSetup::createAttributeMetadataConfig($paths);
* $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'memory' => true], $config);
* $entityManager = new EntityManager($connection, $config);
*
@@ -72,7 +72,7 @@ class EntityManager implements EntityManagerInterface
/**
* The event manager that is the central point of the event system.
*/
private EventManager $eventManager;
private EventManagerInterface $eventManager;
/**
* The proxy factory used to create dynamic proxies.
@@ -113,17 +113,13 @@ class EntityManager implements EntityManagerInterface
public function __construct(
private Connection $conn,
private Configuration $config,
EventManager|null $eventManager = null,
EventManagerInterface|null $eventManager = null,
) {
if (! $config->getMetadataDriverImpl()) {
throw MissingMappingDriverImplementation::create();
}
$this->eventManager = $eventManager
?? (method_exists($conn, 'getEventManager')
? $conn->getEventManager()
: new EventManager()
);
$this->eventManager = $eventManager ?? new EventManager();
$metadataFactoryClassName = $config->getClassMetadataFactoryName();
@@ -134,12 +130,7 @@ class EntityManager implements EntityManagerInterface
$this->repositoryFactory = $config->getRepositoryFactory();
$this->unitOfWork = new UnitOfWork($this);
$this->proxyFactory = new ProxyFactory(
$this,
$config->getProxyDir(),
$config->getProxyNamespace(),
$config->getAutoGenerateProxyClasses(),
);
$this->proxyFactory = new ProxyFactory($this);
if ($config->isSecondLevelCacheEnabled()) {
$cacheConfig = $config->getSecondLevelCacheConfiguration();
@@ -148,31 +139,37 @@ class EntityManager implements EntityManagerInterface
}
}
#[Override]
public function getConnection(): Connection
{
return $this->conn;
}
#[Override]
public function getMetadataFactory(): ClassMetadataFactory
{
return $this->metadataFactory;
}
#[Override]
public function getExpressionBuilder(): Expr
{
return $this->expressionBuilder ??= new Expr();
}
#[Override]
public function beginTransaction(): void
{
$this->conn->beginTransaction();
}
#[Override]
public function getCache(): Cache|null
{
return $this->cache;
}
#[Override]
public function wrapInTransaction(callable $func): mixed
{
$this->conn->beginTransaction();
@@ -198,11 +195,13 @@ class EntityManager implements EntityManagerInterface
}
}
#[Override]
public function commit(): void
{
$this->conn->commit();
}
#[Override]
public function rollback(): void
{
$this->conn->rollBack();
@@ -215,11 +214,13 @@ class EntityManager implements EntityManagerInterface
*
* {@inheritDoc}
*/
#[Override]
public function getClassMetadata(string $className): Mapping\ClassMetadata
{
return $this->metadataFactory->getMetadataFor($className);
}
#[Override]
public function createQuery(string $dql = ''): Query
{
$query = new Query($this);
@@ -231,6 +232,7 @@ class EntityManager implements EntityManagerInterface
return $query;
}
#[Override]
public function createNativeQuery(string $sql, ResultSetMapping $rsm): NativeQuery
{
$query = new NativeQuery($this);
@@ -241,6 +243,7 @@ class EntityManager implements EntityManagerInterface
return $query;
}
#[Override]
public function createQueryBuilder(): QueryBuilder
{
return new QueryBuilder($this);
@@ -258,6 +261,7 @@ class EntityManager implements EntityManagerInterface
* makes use of optimistic locking fails.
* @throws ORMException
*/
#[Override]
public function flush(): void
{
$this->errorIfClosed();
@@ -267,7 +271,8 @@ class EntityManager implements EntityManagerInterface
/**
* {@inheritDoc}
*/
public function find($className, mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null
#[Override]
public function find($className, mixed $id, LockMode|null $lockMode = null, int|null $lockVersion = null): object|null
{
$class = $this->metadataFactory->getMetadataFor(ltrim($className, '\\'));
@@ -285,7 +290,7 @@ class EntityManager implements EntityManagerInterface
foreach ($id as $i => $value) {
if (is_object($value)) {
$className = DefaultProxyClassNameResolver::getClass($value);
$className = $value::class;
if ($this->metadataFactory->hasMetadataFor($className)) {
$id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
@@ -363,6 +368,7 @@ class EntityManager implements EntityManagerInterface
}
}
#[Override]
public function getReference(string $entityName, mixed $id): object|null
{
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
@@ -408,11 +414,13 @@ class EntityManager implements EntityManagerInterface
* Clears the EntityManager. All entities that are currently managed
* by this EntityManager become detached.
*/
#[Override]
public function clear(): void
{
$this->unitOfWork->clear();
}
#[Override]
public function close(): void
{
$this->clear();
@@ -432,6 +440,7 @@ class EntityManager implements EntityManagerInterface
* @throws ORMInvalidArgumentException
* @throws ORMException
*/
#[Override]
public function persist(object $object): void
{
$this->errorIfClosed();
@@ -448,6 +457,7 @@ class EntityManager implements EntityManagerInterface
* @throws ORMInvalidArgumentException
* @throws ORMException
*/
#[Override]
public function remove(object $object): void
{
$this->errorIfClosed();
@@ -455,7 +465,8 @@ class EntityManager implements EntityManagerInterface
$this->unitOfWork->remove($object);
}
public function refresh(object $object, LockMode|int|null $lockMode = null): void
#[Override]
public function refresh(object $object, LockMode|null $lockMode = null): void
{
$this->errorIfClosed();
@@ -471,12 +482,14 @@ class EntityManager implements EntityManagerInterface
*
* @throws ORMInvalidArgumentException
*/
#[Override]
public function detach(object $object): void
{
$this->unitOfWork->detach($object);
}
public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|int|null $lockVersion = null): void
#[Override]
public function lock(object $entity, LockMode $lockMode, DateTimeInterface|int|null $lockVersion = null): void
{
$this->unitOfWork->lock($entity, $lockMode, $lockVersion);
}
@@ -490,6 +503,7 @@ class EntityManager implements EntityManagerInterface
*
* @template T of object
*/
#[Override]
public function getRepository(string $className): EntityRepository
{
return $this->repositoryFactory->getRepository($this, $className);
@@ -500,6 +514,7 @@ class EntityManager implements EntityManagerInterface
*
* @return bool TRUE if this EntityManager currently manages the given entity, FALSE otherwise.
*/
#[Override]
public function contains(object $object): bool
{
return $this->unitOfWork->isScheduledForInsert($object)
@@ -507,11 +522,13 @@ class EntityManager implements EntityManagerInterface
&& ! $this->unitOfWork->isScheduledForDelete($object);
}
public function getEventManager(): EventManager
#[Override]
public function getEventManager(): EventManagerInterface
{
return $this->eventManager;
}
#[Override]
public function getConfiguration(): Configuration
{
return $this->config;
@@ -529,16 +546,19 @@ class EntityManager implements EntityManagerInterface
}
}
#[Override]
public function isOpen(): bool
{
return ! $this->closed;
}
#[Override]
public function getUnitOfWork(): UnitOfWork
{
return $this->unitOfWork;
}
#[Override]
public function newHydrator(string|int $hydrationMode): AbstractHydrator
{
return match ($hydrationMode) {
@@ -552,11 +572,13 @@ class EntityManager implements EntityManagerInterface
};
}
#[Override]
public function getProxyFactory(): ProxyFactory
{
return $this->proxyFactory;
}
#[Override]
public function initializeObject(object $obj): void
{
$this->unitOfWork->initializeObject($obj);
@@ -565,33 +587,35 @@ class EntityManager implements EntityManagerInterface
/**
* {@inheritDoc}
*/
#[Override]
public function isUninitializedObject($value): bool
{
return $this->unitOfWork->isUninitializedObject($value);
}
#[Override]
public function getFilters(): FilterCollection
{
return $this->filterCollection ??= new FilterCollection($this);
}
#[Override]
public function isFiltersStateClean(): bool
{
return $this->filterCollection === null || $this->filterCollection->isClean();
}
#[Override]
public function hasFilters(): bool
{
return $this->filterCollection !== null;
}
/**
* @phpstan-param LockMode::* $lockMode
*
* @throws OptimisticLockException
* @throws TransactionRequiredException
*/
private function checkLockRequirements(LockMode|int $lockMode, ClassMetadata $class): void
private function checkLockRequirements(LockMode $lockMode, ClassMetadata $class): void
{
switch ($lockMode) {
case LockMode::OPTIMISTIC:

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Doctrine\ORM;
use DateTimeInterface;
use Doctrine\Common\EventManager;
use Doctrine\Common\EventManagerInterface;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\Exception\ORMException;
@@ -16,6 +16,7 @@ use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\FilterCollection;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\ObjectManager;
use Override;
interface EntityManagerInterface extends ObjectManager
{
@@ -28,6 +29,7 @@ interface EntityManagerInterface extends ObjectManager
*
* @template T of object
*/
#[Override]
public function getRepository(string $className): EntityRepository;
/**
@@ -40,6 +42,7 @@ interface EntityManagerInterface extends ObjectManager
*/
public function getConnection(): Connection;
#[Override]
public function getMetadataFactory(): ClassMetadataFactory;
/**
@@ -110,15 +113,13 @@ interface EntityManagerInterface extends ObjectManager
/**
* Finds an Entity by its identifier.
*
* @param string $className The class name of the entity to find.
* @param mixed $id The identity of the entity to find.
* @param LockMode|int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
* or NULL if no specific lock mode should be used
* during the search.
* @param int|null $lockVersion The version of the entity to find when using
* optimistic locking.
* @param string $className The class name of the entity to find.
* @param mixed $id The identity of the entity to find.
* @param LockMode|null $lockMode The lock mode or NULL if no specific lock mode
* should be used during the search.
* @param int|null $lockVersion The version of the entity to find when using
* optimistic locking.
* @phpstan-param class-string<T> $className
* @phpstan-param LockMode::*|null $lockMode
*
* @return object|null The entity instance or NULL if the entity can not be found.
* @phpstan-return T|null
@@ -130,22 +131,22 @@ interface EntityManagerInterface extends ObjectManager
*
* @template T of object
*/
public function find(string $className, mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null;
#[Override]
public function find(string $className, mixed $id, LockMode|null $lockMode = null, int|null $lockVersion = null): object|null;
/**
* Refreshes the persistent state of an object from the database,
* overriding any local changes that have not yet been persisted.
*
* @param LockMode|int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
* or NULL if no specific lock mode should be used
* during the search.
* @phpstan-param LockMode::*|null $lockMode
* @param LockMode|null $lockMode The lock mode or NULL if no specific lock mode
* should be used during the search.
*
* @throws ORMInvalidArgumentException
* @throws ORMException
* @throws TransactionRequiredException
*/
public function refresh(object $object, LockMode|int|null $lockMode = null): void;
#[Override]
public function refresh(object $object, LockMode|null $lockMode = null): void;
/**
* Gets a reference to the entity identified by the given type and identifier
@@ -172,17 +173,15 @@ interface EntityManagerInterface extends ObjectManager
/**
* Acquire a lock on the given entity.
*
* @phpstan-param LockMode::* $lockMode
*
* @throws OptimisticLockException
* @throws PessimisticLockException
*/
public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|int|null $lockVersion = null): void;
public function lock(object $entity, LockMode $lockMode, DateTimeInterface|int|null $lockVersion = null): void;
/**
* Gets the EventManager used by the EntityManager.
* Gets the EventManagerInterface used by the EntityManager.
*/
public function getEventManager(): EventManager;
public function getEventManager(): EventManagerInterface;
/**
* Gets the Configuration used by the EntityManager.
@@ -237,5 +236,6 @@ interface EntityManagerInterface extends ObjectManager
*
* @phpstan-template T of object
*/
#[Override]
public function getClassMetadata(string $className): Mapping\ClassMetadata;
}

View File

@@ -15,6 +15,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\ORM\Repository\Exception\InvalidMagicMethodCall;
use Doctrine\Persistence\ObjectRepository;
use Override;
use function array_slice;
use function lcfirst;
@@ -73,15 +74,14 @@ class EntityRepository implements ObjectRepository, Selectable
/**
* Finds an entity by its primary key / identifier.
*
* @param LockMode|int|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
* or NULL if no specific lock mode should be used
* during the search.
* @phpstan-param LockMode::*|null $lockMode
* @param LockMode|null $lockMode The lock mode or NULL if no specific lock mode
* should be used during the search.
*
* @return object|null The entity instance or NULL if the entity can not be found.
* @phpstan-return ?T
*/
public function find(mixed $id, LockMode|int|null $lockMode = null, int|null $lockVersion = null): object|null
#[Override]
public function find(mixed $id, LockMode|null $lockMode = null, int|null $lockVersion = null): object|null
{
return $this->em->find($this->entityName, $id, $lockMode, $lockVersion);
}
@@ -91,6 +91,7 @@ class EntityRepository implements ObjectRepository, Selectable
*
* @phpstan-return list<T> The entities.
*/
#[Override]
public function findAll(): array
{
return $this->findBy([]);
@@ -103,6 +104,7 @@ class EntityRepository implements ObjectRepository, Selectable
*
* @phpstan-return list<T>
*/
#[Override]
public function findBy(array $criteria, array|null $orderBy = null, int|null $limit = null, int|null $offset = null): array
{
$persister = $this->em->getUnitOfWork()->getEntityPersister($this->entityName);
@@ -118,6 +120,7 @@ class EntityRepository implements ObjectRepository, Selectable
*
* @phpstan-return T|null
*/
#[Override]
public function findOneBy(array $criteria, array|null $orderBy = null): object|null
{
$persister = $this->em->getUnitOfWork()->getEntityPersister($this->entityName);
@@ -175,6 +178,7 @@ class EntityRepository implements ObjectRepository, Selectable
return $this->entityName;
}
#[Override]
public function getClassName(): string
{
return $this->getEntityName();
@@ -197,6 +201,7 @@ class EntityRepository implements ObjectRepository, Selectable
*
* @phpstan-return AbstractLazyCollection<int, T>&Selectable<int, T>
*/
#[Override]
public function matching(Criteria $criteria): AbstractLazyCollection&Selectable
{
$persister = $this->em->getUnitOfWork()->getEntityPersister($this->entityName);

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Doctrine\ORM\Event;
use Doctrine\Common\EventArgs;
use Doctrine\Common\EventManager;
use Doctrine\Common\EventDispatcher;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\EntityListenerResolver;
@@ -15,21 +15,21 @@ use Doctrine\ORM\Mapping\EntityListenerResolver;
*/
class ListenersInvoker
{
final public const INVOKE_NONE = 0;
final public const INVOKE_LISTENERS = 1;
final public const INVOKE_CALLBACKS = 2;
final public const INVOKE_MANAGER = 4;
final public const int INVOKE_NONE = 0;
final public const int INVOKE_LISTENERS = 1;
final public const int INVOKE_CALLBACKS = 2;
final public const int INVOKE_MANAGER = 4;
/** The Entity listener resolver. */
private readonly EntityListenerResolver $resolver;
/** The EventManager used for dispatching events. */
private readonly EventManager $eventManager;
/** The EventDispatcher used for dispatching events. */
private readonly EventDispatcher $eventDispatcher;
public function __construct(EntityManagerInterface $em)
{
$this->eventManager = $em->getEventManager();
$this->resolver = $em->getConfiguration()->getEntityListenerResolver();
$this->eventDispatcher = $em->getEventManager();
$this->resolver = $em->getConfiguration()->getEntityListenerResolver();
}
/**
@@ -52,7 +52,7 @@ class ListenersInvoker
$invoke |= self::INVOKE_LISTENERS;
}
if ($this->eventManager->hasListeners($eventName)) {
if ($this->eventDispatcher->hasListeners($eventName)) {
$invoke |= self::INVOKE_MANAGER;
}
@@ -92,7 +92,7 @@ class ListenersInvoker
}
if ($invoke & self::INVOKE_MANAGER) {
$this->eventManager->dispatchEvent($eventName, $event);
$this->eventDispatcher->dispatchEvent($eventName, $event);
}
}
}

View File

@@ -24,7 +24,7 @@ final class Events
*
* This is an entity lifecycle event.
*/
public const preRemove = 'preRemove';
final public const string preRemove = 'preRemove';
/**
* The postRemove event occurs for an entity after the entity has
@@ -32,7 +32,7 @@ final class Events
*
* This is an entity lifecycle event.
*/
public const postRemove = 'postRemove';
final public const string postRemove = 'postRemove';
/**
* The prePersist event occurs for a given entity before the respective
@@ -40,7 +40,7 @@ final class Events
*
* This is an entity lifecycle event.
*/
public const prePersist = 'prePersist';
final public const string prePersist = 'prePersist';
/**
* The postPersist event occurs for an entity after the entity has
@@ -49,7 +49,7 @@ final class Events
*
* This is an entity lifecycle event.
*/
public const postPersist = 'postPersist';
final public const string postPersist = 'postPersist';
/**
* The preUpdate event occurs before the database update operations to
@@ -57,7 +57,7 @@ final class Events
*
* This is an entity lifecycle event.
*/
public const preUpdate = 'preUpdate';
final public const string preUpdate = 'preUpdate';
/**
* The postUpdate event occurs after the database update operations to
@@ -65,7 +65,7 @@ final class Events
*
* This is an entity lifecycle event.
*/
public const postUpdate = 'postUpdate';
final public const string postUpdate = 'postUpdate';
/**
* The postLoad event occurs for an entity after the entity has been loaded
@@ -78,26 +78,26 @@ final class Events
*
* This is an entity lifecycle event.
*/
public const postLoad = 'postLoad';
final public const string postLoad = 'postLoad';
/**
* The loadClassMetadata event occurs after the mapping metadata for a class
* has been loaded from a mapping source (attributes/xml).
*/
public const loadClassMetadata = 'loadClassMetadata';
final public const string loadClassMetadata = 'loadClassMetadata';
/**
* The onClassMetadataNotFound event occurs whenever loading metadata for a class
* failed.
*/
public const onClassMetadataNotFound = 'onClassMetadataNotFound';
final public const string onClassMetadataNotFound = 'onClassMetadataNotFound';
/**
* The preFlush event occurs when the EntityManager#flush() operation is invoked,
* but before any changes to managed entities have been calculated. This event is
* always raised right after EntityManager#flush() call.
*/
public const preFlush = 'preFlush';
final public const string preFlush = 'preFlush';
/**
* The onFlush event occurs when the EntityManager#flush() operation is invoked,
@@ -105,7 +105,7 @@ final class Events
* actual database operations are executed. The event is only raised if there is
* actually something to do for the underlying UnitOfWork.
*/
public const onFlush = 'onFlush';
final public const string onFlush = 'onFlush';
/**
* The postFlush event occurs when the EntityManager#flush() operation is invoked and
@@ -113,11 +113,11 @@ final class Events
* actually something to do for the underlying UnitOfWork. The event won't be raised if an error occurs during the
* flush operation.
*/
public const postFlush = 'postFlush';
final public const string postFlush = 'postFlush';
/**
* The onClear event occurs when the EntityManager#clear() operation is invoked,
* after all references to entities have been removed from the unit of work.
*/
public const onClear = 'onClear';
final public const string onClear = 'onClear';
}

View File

@@ -11,7 +11,7 @@ use function sprintf;
final class MultipleSelectorsFoundException extends LogicException implements ORMException
{
public const MULTIPLE_SELECTORS_FOUND_EXCEPTION = 'Multiple selectors found: %s. Please select only one.';
final public const string MULTIPLE_SELECTORS_FOUND_EXCEPTION = 'Multiple selectors found: %s. Please select only one.';
/** @param string[] $selectors */
public static function create(array $selectors): self

View File

@@ -1,44 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\ORM\Exception;
use LogicException;
use function sprintf;
/** @deprecated */
final class NotSupported extends LogicException implements ORMException
{
public static function create(): self
{
return new self('This behaviour is (currently) not supported by Doctrine 2');
}
public static function createForDbal3(string $context): self
{
return new self(sprintf(
<<<'EXCEPTION'
Context: %s
Problem: Feature was deprecated in doctrine/dbal 2.x and is not supported by installed doctrine/dbal:3.x
Solution: See the doctrine/deprecations logs for new alternative approaches.
EXCEPTION
,
$context,
));
}
public static function createForPersistence3(string $context): self
{
return new self(sprintf(
<<<'EXCEPTION'
Context: %s
Problem: Feature was deprecated in doctrine/persistence 2.x and is not supported by installed doctrine/persistence:3.x
Solution: See the doctrine/deprecations logs for new alternative approaches.
EXCEPTION
,
$context,
));
}
}

View File

@@ -6,6 +6,7 @@ namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Exception\EntityMissingAssignedId;
use Override;
/**
* Special generator for application-assigned identifiers (doesn't really generate anything).
@@ -19,6 +20,7 @@ class AssignedGenerator extends AbstractIdGenerator
*
* @throws EntityMissingAssignedId
*/
#[Override]
public function generateId(EntityManagerInterface $em, object|null $entity): array
{
$class = $em->getClassMetadata($entity::class);

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManagerInterface;
use Override;
/**
* Id generator that obtains IDs from special "identity" columns. These are columns
@@ -13,11 +14,13 @@ use Doctrine\ORM\EntityManagerInterface;
*/
class BigIntegerIdentityGenerator extends AbstractIdGenerator
{
#[Override]
public function generateId(EntityManagerInterface $em, object|null $entity): string
{
return (string) $em->getConnection()->lastInsertId();
}
#[Override]
public function isPostInsertGenerator(): bool
{
return true;

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Doctrine\ORM\Id;
use Doctrine\ORM\EntityManagerInterface;
use Override;
/**
* Id generator that obtains IDs from special "identity" columns. These are columns
@@ -13,11 +14,13 @@ use Doctrine\ORM\EntityManagerInterface;
*/
class IdentityGenerator extends AbstractIdGenerator
{
#[Override]
public function generateId(EntityManagerInterface $em, object|null $entity): int
{
return (int) $em->getConnection()->lastInsertId();
}
#[Override]
public function isPostInsertGenerator(): bool
{
return true;

View File

@@ -5,17 +5,13 @@ declare(strict_types=1);
namespace Doctrine\ORM\Id;
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
use Doctrine\Deprecations\Deprecation;
use Doctrine\ORM\EntityManagerInterface;
use Serializable;
use function serialize;
use function unserialize;
use Override;
/**
* Represents an ID generator that uses a database sequence.
*/
class SequenceGenerator extends AbstractIdGenerator implements Serializable
class SequenceGenerator extends AbstractIdGenerator
{
private int $nextValue = 0;
private int|null $maxValue = null;
@@ -32,6 +28,7 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
) {
}
#[Override]
public function generateId(EntityManagerInterface $em, object|null $entity): int
{
if ($this->maxValue === null || $this->nextValue === $this->maxValue) {
@@ -66,20 +63,6 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
return $this->nextValue;
}
/** @deprecated without replacement. */
final public function serialize(): string
{
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/11468',
'%s() is deprecated, use __serialize() instead. %s won\'t implement the Serializable interface anymore in ORM 4.',
__METHOD__,
self::class,
);
return serialize($this->__serialize());
}
/** @return array<string, mixed> */
public function __serialize(): array
{
@@ -89,20 +72,6 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
];
}
/** @deprecated without replacement. */
final public function unserialize(string $serialized): void
{
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/11468',
'%s() is deprecated, use __unserialize() instead. %s won\'t implement the Serializable interface anymore in ORM 4.',
__METHOD__,
self::class,
);
$this->__unserialize(unserialize($serialized));
}
/** @param array<string, mixed> $data */
public function __unserialize(array $data): void
{

View File

@@ -17,15 +17,18 @@ use Doctrine\ORM\UnitOfWork;
use Generator;
use LogicException;
use ReflectionClass;
use ReflectionEnum;
use function array_key_exists;
use function array_keys;
use function array_map;
use function array_merge;
use function count;
use function current;
use function end;
use function in_array;
use function is_array;
use function is_object;
use function ksort;
/**
@@ -126,8 +129,10 @@ abstract class AbstractHydrator
} else {
yield from $result;
}
} else {
} elseif (is_object(current($result))) {
yield $result;
} else {
yield array_merge(...$result);
}
}
} finally {
@@ -593,13 +598,18 @@ abstract class AbstractHydrator
*/
final protected function buildEnum(mixed $value, string $enumType): BackedEnum|array
{
$reflection = new ReflectionEnum($enumType);
$isIntBacked = $reflection->isBacked() && $reflection->getBackingType()->getName() === 'int';
if (is_array($value)) {
return array_map(
static fn ($value) => $enumType::from($value),
static fn ($value) => $enumType::from($isIntBacked ? (int) $value : $value),
$value,
);
}
$value = $isIntBacked ? (int) $value : $value;
return $enumType::from($value);
}
}

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Doctrine\ORM\Internal\Hydration;
use Override;
use function array_key_last;
use function count;
use function is_array;
@@ -32,6 +34,7 @@ class ArrayHydrator extends AbstractHydrator
private int $resultCounter = 0;
#[Override]
protected function prepare(): void
{
$this->isSimpleQuery = count($this->resultSetMapping()->aliasMap) <= 1;
@@ -46,6 +49,7 @@ class ArrayHydrator extends AbstractHydrator
/**
* {@inheritDoc}
*/
#[Override]
protected function hydrateAllData(): array
{
$result = [];
@@ -60,6 +64,7 @@ class ArrayHydrator extends AbstractHydrator
/**
* {@inheritDoc}
*/
#[Override]
protected function hydrateRowData(array $row, array &$result): void
{
// 1) Initialize

View File

@@ -10,6 +10,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use Override;
use function array_fill_keys;
use function array_keys;
@@ -51,6 +52,7 @@ class ObjectHydrator extends AbstractHydrator
/** @var mixed[] */
private array $existingCollections = [];
#[Override]
protected function prepare(): void
{
if (! isset($this->hints[UnitOfWork::HINT_DEFEREAGERLOAD])) {
@@ -108,6 +110,7 @@ class ObjectHydrator extends AbstractHydrator
}
}
#[Override]
protected function cleanup(): void
{
$eagerLoad = isset($this->hints[UnitOfWork::HINT_DEFEREAGERLOAD]) && $this->hints[UnitOfWork::HINT_DEFEREAGERLOAD] === true;
@@ -127,6 +130,7 @@ class ObjectHydrator extends AbstractHydrator
$this->uow->hydrationComplete();
}
#[Override]
protected function cleanupAfterRowIteration(): void
{
$this->identifierMap =
@@ -139,6 +143,7 @@ class ObjectHydrator extends AbstractHydrator
/**
* {@inheritDoc}
*/
#[Override]
protected function hydrateAllData(): array
{
$result = [];
@@ -318,6 +323,7 @@ class ObjectHydrator extends AbstractHydrator
* @param mixed[] $row The data of the row to process.
* @param mixed[] $result The result array to fill.
*/
#[Override]
protected function hydrateRowData(array $row, array &$result): void
{
// Initialize
@@ -574,6 +580,7 @@ class ObjectHydrator extends AbstractHydrator
}
/** @param mixed[] $data pre-hydrated SQL Result Row. */
#[Override]
protected function hydrateNestedEntity(array $data, string $dqlAlias): mixed
{
if (isset($this->resultSetMapping()->nestedEntities[$dqlAlias])) {
@@ -587,6 +594,7 @@ class ObjectHydrator extends AbstractHydrator
* When executed in a hydrate() loop we may have to clear internal state to
* decrease memory consumption.
*/
#[Override]
public function onClear(mixed $eventArgs): void
{
parent::onClear($eventArgs);

View File

@@ -6,8 +6,8 @@ namespace Doctrine\ORM\Internal\Hydration;
use Doctrine\DBAL\Driver\Exception;
use Doctrine\ORM\Exception\MultipleSelectorsFoundException;
use Override;
use function array_column;
use function count;
/**
@@ -21,14 +21,13 @@ final class ScalarColumnHydrator extends AbstractHydrator
* @throws MultipleSelectorsFoundException
* @throws Exception
*/
#[Override]
protected function hydrateAllData(): array
{
if (count($this->resultSetMapping()->fieldMappings) > 1) {
throw MultipleSelectorsFoundException::create($this->resultSetMapping()->fieldMappings);
}
$result = $this->statement()->fetchAllNumeric();
return array_column($result, 0);
return $this->statement()->fetchFirstColumn();
}
}

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Doctrine\ORM\Internal\Hydration;
use Override;
/**
* Hydrator that produces flat, rectangular results of scalar data.
* The created result is almost the same as a regular SQL result set, except
@@ -14,6 +16,7 @@ class ScalarHydrator extends AbstractHydrator
/**
* {@inheritDoc}
*/
#[Override]
protected function hydrateAllData(): array
{
$result = [];
@@ -28,6 +31,7 @@ class ScalarHydrator extends AbstractHydrator
/**
* {@inheritDoc}
*/
#[Override]
protected function hydrateRowData(array $row, array &$result): void
{
$result[] = $this->gatherScalarRowData($row);

View File

@@ -9,6 +9,7 @@ use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\ORM\Query;
use Exception;
use Override;
use RuntimeException;
use ValueError;
@@ -28,6 +29,7 @@ class SimpleObjectHydrator extends AbstractHydrator
private ClassMetadata|null $class = null;
#[Override]
protected function prepare(): void
{
if (count($this->resultSetMapping()->aliasMap) !== 1) {
@@ -41,6 +43,7 @@ class SimpleObjectHydrator extends AbstractHydrator
$this->class = $this->getClassMetadata(reset($this->resultSetMapping()->aliasMap));
}
#[Override]
protected function cleanup(): void
{
parent::cleanup();
@@ -52,6 +55,7 @@ class SimpleObjectHydrator extends AbstractHydrator
/**
* {@inheritDoc}
*/
#[Override]
protected function hydrateAllData(): array
{
$result = [];
@@ -68,6 +72,7 @@ class SimpleObjectHydrator extends AbstractHydrator
/**
* {@inheritDoc}
*/
#[Override]
protected function hydrateRowData(array $row, array &$result): void
{
assert($this->class !== null);

View File

@@ -6,6 +6,7 @@ namespace Doctrine\ORM\Internal\Hydration;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException;
use Override;
use function array_shift;
use function count;
@@ -16,6 +17,7 @@ use function key;
*/
class SingleScalarHydrator extends AbstractHydrator
{
#[Override]
protected function hydrateAllData(): mixed
{
$data = $this->statement()->fetchAllAssociative();

View File

@@ -25,9 +25,9 @@ use function spl_object_id;
*/
final class StronglyConnectedComponents
{
private const NOT_VISITED = 1;
private const IN_PROGRESS = 2;
private const VISITED = 3;
private const int NOT_VISITED = 1;
private const int IN_PROGRESS = 2;
private const int VISITED = 3;
/**
* Array of all nodes, indexed by object ids.

View File

@@ -20,9 +20,9 @@ use function spl_object_id;
*/
final class TopologicalSort
{
private const NOT_VISITED = 1;
private const IN_PROGRESS = 2;
private const VISITED = 3;
private const int NOT_VISITED = 1;
private const int IN_PROGRESS = 2;
private const int VISITED = 3;
/**
* Array of all nodes, indexed by object ids.

View File

@@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace Doctrine\ORM\Internal\UnitOfWork;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Id\AssignedGenerator;
use Doctrine\ORM\Mapping\ClassMetadata;
/**
* An {@see InsertBatch} represents a set of entities that are safe to be batched
* together in a single query.
*
* These entities are only those that have all fields already assigned, including the
* identifier field(s).
*
* This data structure only exists for internal {@see UnitOfWork} optimisations, and
* should not be relied upon outside the ORM.
*
* @internal
*
* @template TEntity of object
*/
final class InsertBatch
{
/**
* @param ClassMetadata<TEntity> $class
* @param non-empty-list<TEntity> $entities
*/
public function __construct(
public readonly ClassMetadata $class,
public array $entities,
) {
}
/**
* Note: Code in here is procedural/ugly due to it being in a hot path of the {@see UnitOfWork}
*
* This method will batch the given entity set by type, preserving their order. For example,
* given an input [A1, A2, A3, B1, B2, A4, A5], it will create an [[A1, A2, A3], [B1, B2], [A4, A5]] batch.
*
* Entities for which the identifier needs to be generated or fetched by a sequence are put as single
* items in a batch of their own, since it is unsafe to batch-insert them.
*
* @param list<TEntities> $entities
*
* @return list<self<TEntities>>
*
* @template TEntities of object
*/
public static function batchByEntityType(
EntityManagerInterface $entityManager,
array $entities,
): array {
$currentClass = null;
$batches = [];
$batchIndex = -1;
foreach ($entities as $entity) {
$entityClass = $entityManager->getClassMetadata($entity::class);
if (
$currentClass?->name !== $entityClass->name
|| ! $entityClass->idGenerator instanceof AssignedGenerator
) {
$currentClass = $entityClass;
$batches[] = new InsertBatch($entityClass, [$entity]);
$batchIndex += 1;
continue;
}
$batches[$batchIndex]->entities[] = $entity;
}
return $batches;
}
}

View File

@@ -10,8 +10,7 @@ use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\ReadableCollection;
use Doctrine\Common\Collections\Selectable;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use function assert;
use Override;
/**
* A lazy collection that allows a fast count when using criteria object
@@ -26,6 +25,7 @@ use function assert;
*/
class LazyCriteriaCollection extends AbstractLazyCollection implements Selectable
{
/** @var non-negative-int|null */
private int|null $count = null;
public function __construct(
@@ -37,6 +37,7 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
/**
* Do an efficient count on the collection
*/
#[Override]
public function count(): int
{
if ($this->isInitialized()) {
@@ -54,6 +55,7 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
/**
* check if collection is empty without loading it
*/
#[Override]
public function isEmpty(): bool
{
if ($this->isInitialized()) {
@@ -70,6 +72,7 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
*
* @return bool TRUE if the collection contains $element, FALSE otherwise.
*/
#[Override]
public function contains(mixed $element): bool
{
if ($this->isInitialized()) {
@@ -80,14 +83,15 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
}
/** @return ReadableCollection<TKey, TValue>&Selectable<TKey, TValue> */
#[Override]
public function matching(Criteria $criteria): ReadableCollection&Selectable
{
$this->initialize();
assert($this->collection instanceof Selectable);
return $this->collection->matching($criteria);
}
#[Override]
protected function doInitialize(): void
{
$elements = $this->entityPersister->loadCriteria($this->criteria);

View File

@@ -6,6 +6,7 @@ namespace Doctrine\ORM\Mapping;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\ORM\Internal\SQLResultCasing;
use Override;
/**
* ANSI compliant quote strategy, this strategy does not apply any quote.
@@ -15,6 +16,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
{
use SQLResultCasing;
#[Override]
public function getColumnName(
string $fieldName,
ClassMetadata $class,
@@ -23,6 +25,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
return $class->fieldMappings[$fieldName]->columnName;
}
#[Override]
public function getTableName(ClassMetadata $class, AbstractPlatform $platform): string
{
return $class->table['name'];
@@ -31,16 +34,19 @@ class AnsiQuoteStrategy implements QuoteStrategy
/**
* {@inheritDoc}
*/
#[Override]
public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform): string
{
return $definition['sequenceName'];
}
#[Override]
public function getJoinColumnName(JoinColumnMapping $joinColumn, ClassMetadata $class, AbstractPlatform $platform): string
{
return $joinColumn->name;
}
#[Override]
public function getReferencedJoinColumnName(
JoinColumnMapping $joinColumn,
ClassMetadata $class,
@@ -49,6 +55,7 @@ class AnsiQuoteStrategy implements QuoteStrategy
return $joinColumn->referencedColumnName;
}
#[Override]
public function getJoinTableName(
ManyToManyOwningSideMapping $association,
ClassMetadata $class,
@@ -60,11 +67,13 @@ class AnsiQuoteStrategy implements QuoteStrategy
/**
* {@inheritDoc}
*/
#[Override]
public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform): array
{
return $class->identifier;
}
#[Override]
public function getColumnAlias(
string $columnName,
int $counter,

View File

@@ -1,70 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\ORM\Mapping;
use Doctrine\Deprecations\Deprecation;
use InvalidArgumentException;
use function property_exists;
/** @internal */
trait ArrayAccessImplementation
{
/** @param string $offset */
public function offsetExists(mixed $offset): bool
{
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/11211',
'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.',
static::class,
);
return isset($this->$offset);
}
/** @param string $offset */
public function offsetGet(mixed $offset): mixed
{
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/11211',
'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.',
static::class,
);
if (! property_exists($this, $offset)) {
throw new InvalidArgumentException('Undefined property: ' . $offset);
}
return $this->$offset;
}
/** @param string $offset */
public function offsetSet(mixed $offset, mixed $value): void
{
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/11211',
'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.',
static::class,
);
$this->$offset = $value;
}
/** @param string $offset */
public function offsetUnset(mixed $offset): void
{
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/11211',
'Using ArrayAccess on %s is deprecated and will not be possible in Doctrine ORM 4.0. Use the corresponding property instead.',
static::class,
);
$this->$offset = null;
}
}

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Doctrine\ORM\Mapping;
use ArrayAccess;
use Exception;
use OutOfRangeException;
@@ -14,8 +13,7 @@ use function in_array;
use function property_exists;
use function sprintf;
/** @template-implements ArrayAccess<string, mixed> */
abstract class AssociationMapping implements ArrayAccess
abstract class AssociationMapping
{
/**
* The names of persistence operations to cascade on the association.

View File

@@ -113,6 +113,10 @@ class AssociationBuilder
string|null $onDelete = null,
string|null $columnDef = null,
): static {
if ($this->mapping['id'] ?? false) {
$nullable = null;
}
$this->joinColumns[] = [
'name' => $columnName,
'referencedColumnName' => $referencedColumnName,
@@ -133,6 +137,9 @@ class AssociationBuilder
public function makePrimaryKey(): static
{
$this->mapping['id'] = true;
foreach ($this->joinColumns ?? [] as $i => $joinColumn) {
$this->joinColumns[$i]['nullable'] = null;
}
return $this;
}

View File

@@ -17,7 +17,7 @@ use function get_class_methods;
class EntityListenerBuilder
{
/** Hash-map to handle event names. */
private const EVENTS = [
private const array EVENTS = [
Events::preRemove => true,
Events::postRemove => true,
Events::prePersist => true,

View File

@@ -64,6 +64,18 @@ class FieldBuilder
return $this;
}
/**
* Sets indexed.
*
* @return $this
*/
public function index(bool $flag = true): static
{
$this->mapping['index'] = $flag;
return $this;
}
/**
* Sets column name.
*

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Doctrine\ORM\Mapping\Builder;
use Override;
/**
* ManyToMany Association Builder
*
@@ -24,6 +26,31 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
return $this;
}
/**
* Add Join Columns.
*
* @return $this
*/
#[Override]
public function addJoinColumn(
string $columnName,
string $referencedColumnName,
bool $nullable = true,
bool $unique = false,
string|null $onDelete = null,
string|null $columnDef = null,
): static {
$this->joinColumns[] = [
'name' => $columnName,
'referencedColumnName' => $referencedColumnName,
'unique' => $unique,
'onDelete' => $onDelete,
'columnDefinition' => $columnDef,
];
return $this;
}
/**
* Adds Inverse Join Columns.
*
@@ -40,7 +67,6 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
$this->inverseJoinColumns[] = [
'name' => $columnName,
'referencedColumnName' => $referencedColumnName,
'nullable' => $nullable,
'unique' => $unique,
'onDelete' => $onDelete,
'columnDefinition' => $columnDef,
@@ -49,6 +75,7 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
return $this;
}
#[Override]
public function build(): ClassMetadataBuilder
{
$mapping = $this->mapping;

Some files were not shown because too many files have changed in this diff Show More