mirror of
https://github.com/doctrine/orm.git
synced 2026-04-24 06:58:19 +02:00
Compare commits
183 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ed6c2234a | |||
| ff612b9678 | |||
| ee0d7197dd | |||
| 39d2136f46 | |||
| bea454eefc | |||
| 14f2572e4e | |||
| c2c500077b | |||
| 6281c2b79f | |||
| bac1c17eab | |||
| b6137c8911 | |||
| 51be1b1d52 | |||
| 488a5dd3bf | |||
| 896c65504d | |||
| 16a8f10fd2 | |||
| d80a831157 | |||
| 52660297ab | |||
| 58287bb731 | |||
| bc37f75b41 | |||
| 8a25b264f7 | |||
| 0e48b19cd3 | |||
| 109042e5af | |||
| 08328adc6c | |||
| 65806884b0 | |||
| ad80e8281a | |||
| 0c0c61c51b | |||
| cc28fed9f5 | |||
| 2245149588 | |||
| b13564c6c0 | |||
| 91709c1275 | |||
| d18126aac5 | |||
| b7fd8241cf | |||
| 2432939e4f | |||
| 1bf4603422 | |||
| 25d5bc5b46 | |||
| 6cde337777 | |||
| 74ef28295a | |||
| 168ac31084 | |||
| fe4a2e83cf | |||
| 8ac6a13ca0 | |||
| 2707b09a07 | |||
| 121158f92c | |||
| 51ad860a25 | |||
| 9bd51aaeb6 | |||
| c37b115450 | |||
| 19129e9f8a | |||
| 7d01f19667 | |||
| c1bb2ccf4b | |||
| e3d7c6076c | |||
| 40f299f1eb | |||
| d0e9177121 | |||
| 68af854f46 | |||
| 77467cd824 | |||
| 802f20b8e7 | |||
| 96d13ac62a | |||
| 2ea6a1a5fb | |||
| 83851a9716 | |||
| 066ec1ac81 | |||
| 68744489f0 | |||
| cc2ad1993c | |||
| e4d46c4276 | |||
| 858a1adc3b | |||
| 3b499132d9 | |||
| 39153fd88a | |||
| bdc9679e37 | |||
| 87a8ee21c9 | |||
| 59c8bc09ab | |||
| 3a7d7c9f57 | |||
| 06eca40134 | |||
| 23b35e9554 | |||
| e063926cbd | |||
| 4a01a76a17 | |||
| 93c2dd9d4b | |||
| 75bc22980e | |||
| 9696c3434d | |||
| bf3e082c00 | |||
| d31aabb40c | |||
| d66884403f | |||
| 552eae37a3 | |||
| ee4b03aa78 | |||
| eb49f66926 | |||
| c5291b4de8 | |||
| 831d86548c | |||
| f26b3b9cf9 | |||
| 9ab84f7478 | |||
| e6bb4ef20e | |||
| 8b6a58fa0e | |||
| 94986af284 | |||
| ad5c8e4bdc | |||
| c363f55ad1 | |||
| c973a62272 | |||
| 8d3446015a | |||
| 4e335f4044 | |||
| bb36d49b38 | |||
| 2b81a8e260 | |||
| 7d3b3f28e9 | |||
| cbec236e8b | |||
| 306963fe79 | |||
| fb4578406f | |||
| bdc41e2b5e | |||
| 90376a6431 | |||
| b725908c83 | |||
| b274893486 | |||
| 8709fb38b0 | |||
| e9e60f2fbc | |||
| 5f3c1dbab8 | |||
| 6090141e0b | |||
| e4a6c041b5 | |||
| be307edba8 | |||
| c54c557e02 | |||
| 46d0865339 | |||
| 1a5a4c674a | |||
| 95795c87a8 | |||
| 083f642cfa | |||
| db6e702088 | |||
| 716da7e538 | |||
| 5ccbc201bf | |||
| d15624f72f | |||
| 9d1a4973ae | |||
| bcdc5bdaf4 | |||
| 40a0964f06 | |||
| 08a9e60ed0 | |||
| 3e3c023c95 | |||
| 5e6d5c06a9 | |||
| 1622b7877d | |||
| 80aae2796d | |||
| 528ef40fc4 | |||
| 4b4b9b7b6f | |||
| ae842259f5 | |||
| 820a0da4c1 | |||
| fcd02b1ee2 | |||
| a3e3a3bbf3 | |||
| abcad6fa45 | |||
| 1b6cf58a1a | |||
| 6501890ab5 | |||
| e399d21fb3 | |||
| 16f355f0cc | |||
| 94d45a036f | |||
| 9acca2252f | |||
| a809a71aa6 | |||
| bd4449c462 | |||
| e3e96745cc | |||
| 12e0cefba1 | |||
| 21221f73cc | |||
| ab5e9e393b | |||
| e62571c8f4 | |||
| 98f9de2af6 | |||
| 52a6a21387 | |||
| 83c81f6c41 | |||
| 4fc8629414 | |||
| 791667a9e4 | |||
| feb27f00c1 | |||
| abd9186d00 | |||
| 719d007a81 | |||
| 08d3f72755 | |||
| 779781173a | |||
| 76c4539ffa | |||
| 0f8d193512 | |||
| cc314d0fb7 | |||
| c9c493b2fe | |||
| e6eef1a97d | |||
| 8d4718f875 | |||
| c0dfba2ef3 | |||
| 0efac09141 | |||
| efb6cebd41 | |||
| e4769d3191 | |||
| cf408ad9ae | |||
| 7c29078051 | |||
| b59189ab48 | |||
| 401a0c4fe9 | |||
| dba9d72b2d | |||
| fe0647053a | |||
| 7b3db4a037 | |||
| e5e3166747 | |||
| afbf293c94 | |||
| 1d218bae30 | |||
| 7baef1e120 | |||
| 5049b615c5 | |||
| 40fbbf4429 | |||
| 6f98147d09 | |||
| cfadb5499d | |||
| 9ce9ae2818 | |||
| fdb9d44538 | |||
| a9fcaf1d18 |
+34
-4
@@ -6,22 +6,52 @@
|
||||
"docsSlug": "doctrine-orm",
|
||||
"versions": [
|
||||
{
|
||||
"name": "3.0",
|
||||
"branchName": "3.0.x",
|
||||
"name": "4.0",
|
||||
"branchName": "4.0.x",
|
||||
"slug": "latest",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "3.2",
|
||||
"branchName": "3.2.x",
|
||||
"slug": "3.2",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "3.1",
|
||||
"branchName": "3.1.x",
|
||||
"slug": "3.1",
|
||||
"current": true
|
||||
},
|
||||
{
|
||||
"name": "3.0",
|
||||
"branchName": "3.0.x",
|
||||
"slug": "3.0",
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.20",
|
||||
"branchName": "2.20.x",
|
||||
"slug": "2.20",
|
||||
"upcoming": true
|
||||
},
|
||||
{
|
||||
"name": "2.19",
|
||||
"branchName": "2.19.x",
|
||||
"slug": "2.19",
|
||||
"maintained": true
|
||||
},
|
||||
{
|
||||
"name": "2.18",
|
||||
"branchName": "2.18.x",
|
||||
"slug": "2.18",
|
||||
"upcoming": true
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.17",
|
||||
"branchName": "2.17.x",
|
||||
"slug": "2.17",
|
||||
"current": true
|
||||
"maintained": false
|
||||
},
|
||||
{
|
||||
"name": "2.16",
|
||||
|
||||
@@ -24,4 +24,4 @@ on:
|
||||
|
||||
jobs:
|
||||
coding-standards:
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@3.0.0"
|
||||
uses: "doctrine/.github/.github/workflows/coding-standards.yml@5.1.0"
|
||||
|
||||
@@ -40,6 +40,7 @@ jobs:
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
extension:
|
||||
@@ -80,7 +81,7 @@ jobs:
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -97,9 +98,9 @@ jobs:
|
||||
ORM_PROXY_IMPLEMENTATION: "${{ matrix.proxy }}"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v3"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.proxy }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
|
||||
|
||||
@@ -113,6 +114,7 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -162,7 +164,7 @@ jobs:
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -170,9 +172,9 @@ jobs:
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v3"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-${{ matrix.extension }}-coverage"
|
||||
path: "coverage.xml"
|
||||
|
||||
|
||||
@@ -186,11 +188,12 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
mariadb-version:
|
||||
- "10.9"
|
||||
- "11.4"
|
||||
extension:
|
||||
- "mysqli"
|
||||
- "pdo_mysql"
|
||||
@@ -204,11 +207,11 @@ jobs:
|
||||
mariadb:
|
||||
image: "mariadb:${{ matrix.mariadb-version }}"
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: "doctrine_tests"
|
||||
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: yes
|
||||
MARIADB_DATABASE: "doctrine_tests"
|
||||
|
||||
options: >-
|
||||
--health-cmd "mysqladmin ping --silent"
|
||||
--health-cmd "healthcheck.sh --connect --innodb_initialized"
|
||||
|
||||
ports:
|
||||
- "3306:3306"
|
||||
@@ -232,7 +235,7 @@ jobs:
|
||||
extensions: "${{ matrix.extension }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -240,7 +243,7 @@ jobs:
|
||||
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
|
||||
|
||||
- name: "Upload coverage file"
|
||||
uses: "actions/upload-artifact@v3"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage.xml"
|
||||
@@ -256,6 +259,7 @@ jobs:
|
||||
php-version:
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
dbal-version:
|
||||
- "default"
|
||||
- "3@dev"
|
||||
@@ -302,7 +306,7 @@ jobs:
|
||||
if: "${{ matrix.dbal-version != 'default' }}"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
composer-options: "--ignore-platform-req=php+"
|
||||
|
||||
@@ -317,7 +321,7 @@ jobs:
|
||||
ENABLE_SECOND_LEVEL_CACHE: 1
|
||||
|
||||
- name: "Upload coverage files"
|
||||
uses: "actions/upload-artifact@v3"
|
||||
uses: "actions/upload-artifact@v4"
|
||||
with:
|
||||
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
|
||||
path: "coverage*.xml"
|
||||
@@ -348,7 +352,7 @@ jobs:
|
||||
ini-values: "zend.assertions=1, apc.enable_cli=1"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "${{ matrix.deps }}"
|
||||
|
||||
@@ -372,11 +376,13 @@ jobs:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: "Download coverage files"
|
||||
uses: "actions/download-artifact@v3"
|
||||
uses: "actions/download-artifact@v4"
|
||||
with:
|
||||
path: "reports"
|
||||
|
||||
- name: "Upload to Codecov"
|
||||
uses: "codecov/codecov-action@v3"
|
||||
uses: "codecov/codecov-action@v4"
|
||||
with:
|
||||
directory: reports
|
||||
env:
|
||||
CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
|
||||
|
||||
@@ -5,44 +5,16 @@ on:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/documentation.yml
|
||||
- docs/**
|
||||
- ".github/workflows/documentation.yml"
|
||||
- "docs/**"
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
paths:
|
||||
- .github/workflows/documentation.yml
|
||||
- docs/**
|
||||
- ".github/workflows/documentation.yml"
|
||||
- "docs/**"
|
||||
|
||||
jobs:
|
||||
validate-with-guides:
|
||||
name: "Validate documentation with phpDocumentor/guides"
|
||||
runs-on: "ubuntu-22.04"
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: "Install PHP"
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.2"
|
||||
|
||||
- name: "Remove existing composer file"
|
||||
run: "rm composer.json"
|
||||
|
||||
- name: "Require phpdocumentor/guides-cli"
|
||||
run: "composer require --dev phpdocumentor/guides-cli --no-update"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
- name: "Add dummy title to the sidebar"
|
||||
run: |
|
||||
printf '%s\n%s\n\n%s\n' "Dummy title" "===========" "$(cat docs/en/sidebar.rst)" > docs/en/sidebar.rst
|
||||
|
||||
- name: "Run guides-cli"
|
||||
run: "vendor/bin/guides -vvv --no-progress docs/en 2>&1 | grep -v 'Unknown directive' | ( ! grep WARNING )"
|
||||
documentation:
|
||||
name: "Documentation"
|
||||
uses: "doctrine/.github/.github/workflows/documentation.yml@5.1.0"
|
||||
|
||||
@@ -47,15 +47,8 @@ jobs:
|
||||
coverage: "pcov"
|
||||
ini-values: "zend.assertions=1, apc.enable_cli=1"
|
||||
|
||||
- name: "Cache dependencies installed with composer"
|
||||
uses: "actions/cache@v3"
|
||||
with:
|
||||
path: "~/.composer/cache"
|
||||
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
|
||||
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
|
||||
|
||||
- name: "Install dependencies with composer"
|
||||
run: "composer update --no-interaction --no-progress"
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
|
||||
- name: "Run PHPBench"
|
||||
run: "vendor/bin/phpbench run --report=default"
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@3.0.0"
|
||||
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@5.1.0"
|
||||
secrets:
|
||||
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
|
||||
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
|
||||
|
||||
@@ -10,7 +10,7 @@ on:
|
||||
- src/**
|
||||
- phpstan*
|
||||
- psalm*
|
||||
- tests/Doctrine/StaticAnalysis/**
|
||||
- tests/StaticAnalysis/**
|
||||
push:
|
||||
branches:
|
||||
- "*.x"
|
||||
@@ -20,7 +20,7 @@ on:
|
||||
- src/**
|
||||
- phpstan*
|
||||
- psalm*
|
||||
- tests/Doctrine/StaticAnalysis/**
|
||||
- tests/StaticAnalysis/**
|
||||
|
||||
jobs:
|
||||
static-analysis-phpstan:
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.2"
|
||||
php-version: "8.3"
|
||||
|
||||
- name: "Require specific DBAL version"
|
||||
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
run: "composer require doctrine/persistence ^$([ ${{ matrix.persistence-version }} = default ] && echo '3.1' || echo ${{ matrix.persistence-version }}) --no-update"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
@@ -89,13 +89,13 @@ jobs:
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.2"
|
||||
php-version: "8.3"
|
||||
|
||||
- name: "Require specific persistence version"
|
||||
run: "composer require doctrine/persistence ^3.1 --no-update"
|
||||
|
||||
- name: "Install dependencies with Composer"
|
||||
uses: "ramsey/composer-install@v2"
|
||||
uses: "ramsey/composer-install@v3"
|
||||
with:
|
||||
dependency-versions: "highest"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
| [3.0.x][3.0] | [2.18.x][2.18] | [2.17.x][2.17] |
|
||||
|:----------------:|:----------------:|:----------:|
|
||||
| [![Build status][3.0 image]][3.0] | [![Build status][2.18 image]][2.18] | [![Build status][2.17 image]][2.17] |
|
||||
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.18 coverage image]][2.18 coverage] | [![Coverage Status][2.17 coverage image]][2.17 coverage] |
|
||||
| [4.0.x][4.0] | [3.2.x][3.2] | [3.1.x][3.1] | [2.20.x][2.20] | [2.19.x][2.19] |
|
||||
|:------------------------------------------------------:|:------------------------------------------------------:|:------------------------------------------------------:|:--------------------------------------------------------:|:--------------------------------------------------------:|
|
||||
| [![Build status][4.0 image]][4.0] | [![Build status][3.2 image]][3.2] | [![Build status][3.1 image]][3.1] | [![Build status][2.20 image]][2.20] | [![Build status][2.19 image]][2.19] |
|
||||
| [![Coverage Status][4.0 coverage image]][4.0 coverage] | [![Coverage Status][3.2 coverage image]][3.2 coverage] | [![Coverage Status][3.1 coverage image]][3.1 coverage] | [![Coverage Status][2.20 coverage image]][2.20 coverage] | [![Coverage Status][2.19 coverage image]][2.19 coverage] |
|
||||
|
||||
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
|
||||
|
||||
@@ -18,15 +18,23 @@ without requiring unnecessary code duplication.
|
||||
* [Documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/stable/index.html)
|
||||
|
||||
|
||||
[3.0 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.0.x
|
||||
[3.0]: https://github.com/doctrine/orm/tree/3.0.x
|
||||
[3.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.0.x/graph/badge.svg
|
||||
[3.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.0.x
|
||||
[2.18 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.18.x
|
||||
[2.18]: https://github.com/doctrine/orm/tree/2.18.x
|
||||
[2.18 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.18.x/graph/badge.svg
|
||||
[2.18 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.18.x
|
||||
[2.17 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.17.x
|
||||
[2.17]: https://github.com/doctrine/orm/tree/2.17.x
|
||||
[2.17 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.17.x/graph/badge.svg
|
||||
[2.17 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.17.x
|
||||
[4.0 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=4.0.x
|
||||
[4.0]: https://github.com/doctrine/orm/tree/4.0.x
|
||||
[4.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/4.0.x/graph/badge.svg
|
||||
[4.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/4.0.x
|
||||
[3.2 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.2.x
|
||||
[3.2]: https://github.com/doctrine/orm/tree/3.2.x
|
||||
[3.2 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.2.x/graph/badge.svg
|
||||
[3.2 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.2.x
|
||||
[3.1 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.1.x
|
||||
[3.1]: https://github.com/doctrine/orm/tree/3.1.x
|
||||
[3.1 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.1.x/graph/badge.svg
|
||||
[3.1 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.1.x
|
||||
[2.20 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.20.x
|
||||
[2.20]: https://github.com/doctrine/orm/tree/2.20.x
|
||||
[2.20 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.20.x/graph/badge.svg
|
||||
[2.20 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.20.x
|
||||
[2.19 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.19.x
|
||||
[2.19]: https://github.com/doctrine/orm/tree/2.19.x
|
||||
[2.19 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.19.x/graph/badge.svg
|
||||
[2.19 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.19.x
|
||||
|
||||
+53
@@ -1,3 +1,56 @@
|
||||
# Upgrade to 2.20
|
||||
|
||||
## Add `Doctrine\ORM\Query\OutputWalker` interface, deprecate `Doctrine\ORM\Query\SqlWalker::getExecutor()`
|
||||
|
||||
Output walkers should implement the new `\Doctrine\ORM\Query\OutputWalker` interface and create
|
||||
`Doctrine\ORM\Query\Exec\SqlFinalizer` instances instead of `Doctrine\ORM\Query\Exec\AbstractSqlExecutor`s.
|
||||
The output walker must not base its workings on the query `firstResult`/`maxResult` values, so that the
|
||||
`SqlFinalizer` can be kept in the query cache and used regardless of the actual `firstResult`/`maxResult` values.
|
||||
Any operation dependent on `firstResult`/`maxResult` should take place within the `SqlFinalizer::createExecutor()`
|
||||
method. Details can be found at https://github.com/doctrine/orm/pull/11188.
|
||||
|
||||
## Explictly forbid property hooks
|
||||
|
||||
Property hooks are not supported yet by Doctrine ORM. Until support is added,
|
||||
they are explicitly forbidden because the support would result in a breaking
|
||||
change in behavior.
|
||||
|
||||
Progress on this is tracked at https://github.com/doctrine/orm/issues/11624 .
|
||||
|
||||
## PARTIAL DQL syntax is undeprecated
|
||||
|
||||
Use of the PARTIAL keyword is not deprecated anymore in DQL, because we will be
|
||||
able to support PARTIAL objects with PHP 8.4 Lazy Objects and
|
||||
Symfony/VarExporter in a better way. When we decided to remove this feature
|
||||
these two abstractions did not exist yet.
|
||||
|
||||
WARNING: If you want to upgrade to 3.x and still use PARTIAL keyword in DQL
|
||||
with array or object hydrators, then you have to directly migrate to ORM 3.3.x or higher.
|
||||
PARTIAL keyword in DQL is not available in 3.0, 3.1 and 3.2 of ORM.
|
||||
|
||||
## Deprecate `\Doctrine\ORM\Query\Parser::setCustomOutputTreeWalker()`
|
||||
|
||||
Use the `\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER` query hint to set the output walker
|
||||
class instead of setting it through the `\Doctrine\ORM\Query\Parser::setCustomOutputTreeWalker()` method
|
||||
on the parser instance.
|
||||
|
||||
# Upgrade to 2.19
|
||||
|
||||
## Deprecate calling `ClassMetadata::getAssociationMappedByTargetField()` with the owning side of an association
|
||||
|
||||
Calling
|
||||
`Doctrine\ORM\Mapping\ClassMetadata::getAssociationMappedByTargetField()` with
|
||||
the owning side of an association returns `null`, which is undocumented, and
|
||||
wrong according to the phpdoc of the parent method.
|
||||
|
||||
If you do not know whether you are on the owning or inverse side of an association,
|
||||
you can use `Doctrine\ORM\Mapping\ClassMetadata::isAssociationInverseSide()`
|
||||
to find out.
|
||||
|
||||
## Deprecate `Doctrine\ORM\Query\Lexer::T_*` constants
|
||||
|
||||
Use `Doctrine\ORM\Query\TokenType::T_*` instead.
|
||||
|
||||
# Upgrade to 2.17
|
||||
|
||||
## Deprecate annotations classes for named queries
|
||||
|
||||
+6
-3
@@ -15,7 +15,8 @@
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
||||
"phpstan/extension-installer": true
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
@@ -42,14 +43,16 @@
|
||||
"doctrine/annotations": "^1.13 || ^2",
|
||||
"doctrine/coding-standard": "^9.0.2 || ^12.0",
|
||||
"phpbench/phpbench": "^0.16.10 || ^1.0",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.10.35",
|
||||
"phpstan/extension-installer": "~1.1.0 || ^1.4",
|
||||
"phpstan/phpstan": "~1.4.10 || 1.12.6",
|
||||
"phpstan/phpstan-deprecation-rules": "^1",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
|
||||
"psr/log": "^1 || ^2 || ^3",
|
||||
"squizlabs/php_codesniffer": "3.7.2",
|
||||
"symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0",
|
||||
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0",
|
||||
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0",
|
||||
"vimeo/psalm": "4.30.0 || 5.16.0"
|
||||
"vimeo/psalm": "4.30.0 || 5.24.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/annotations": "<1.13 || >= 3.0"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
en/_exts/configurationblock.pyc
|
||||
build
|
||||
en/_build
|
||||
.idea
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "en/_theme"]
|
||||
path = en/_theme
|
||||
url = https://github.com/doctrine/doctrine-sphinx-theme.git
|
||||
Submodule docs/en/_theme deleted from 6f1bc8bead
@@ -99,12 +99,12 @@ discuss it step by step:
|
||||
|
||||
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER); // (2)
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS); // (3)
|
||||
$parser->match(TokenType::T_IDENTIFIER); // (2)
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS); // (3)
|
||||
$this->firstDateExpression = $parser->ArithmeticPrimary(); // (4)
|
||||
$parser->match(Lexer::T_COMMA); // (5)
|
||||
$parser->match(TokenType::T_COMMA); // (5)
|
||||
$this->secondDateExpression = $parser->ArithmeticPrimary(); // (6)
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS); // (3)
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS); // (3)
|
||||
}
|
||||
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
@@ -183,23 +183,23 @@ I'll skip the blah and show the code for this function:
|
||||
|
||||
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstDateExpression = $parser->ArithmeticPrimary();
|
||||
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_COMMA);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
|
||||
$this->intervalExpression = $parser->ArithmeticPrimary();
|
||||
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
|
||||
/** @var Lexer $lexer */
|
||||
$lexer = $parser->getLexer();
|
||||
$this->unit = $lexer->token['value'];
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
|
||||
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Implementing ArrayAccess for Domain Objects
|
||||
===========================================
|
||||
|
||||
.. sectionauthor:: Roman Borschel (roman@code-factory.org)
|
||||
.. sectionauthor:: Roman Borschel <roman@code-factory.org>
|
||||
|
||||
This recipe will show you how to implement ArrayAccess for your
|
||||
domain objects in order to allow more uniform access, for example
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Implementing the Notify ChangeTracking Policy
|
||||
=============================================
|
||||
|
||||
.. sectionauthor:: Roman Borschel (roman@code-factory.org)
|
||||
.. sectionauthor:: Roman Borschel <roman@code-factory.org>
|
||||
|
||||
The NOTIFY change-tracking policy is the most effective
|
||||
change-tracking policy provided by Doctrine but it requires some
|
||||
|
||||
@@ -11,7 +11,7 @@ What we offer are hooks to execute any kind of validation.
|
||||
.. note::
|
||||
|
||||
You don't need to validate your entities in the lifecycle
|
||||
events. Its only one of many options. Of course you can also
|
||||
events. It is only one of many options. Of course you can also
|
||||
perform validations in value setters or any other method of your
|
||||
entities that are used in your code.
|
||||
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ Tutorials
|
||||
Changelogs
|
||||
----------
|
||||
|
||||
* `Upgrade <https://github.com/doctrine/doctrine2/blob/master/UPGRADE.md>`_
|
||||
* `Upgrade <https://github.com/doctrine/orm/blob/HEAD/UPGRADE.md>`_
|
||||
|
||||
Cookbook
|
||||
--------
|
||||
|
||||
@@ -1300,8 +1300,8 @@ This is essentially the same as the following, more verbose, mapping:
|
||||
* @var Collection<int, Group>
|
||||
*/
|
||||
#[JoinTable(name: 'User_Group')]
|
||||
#[JoinColumn(name: 'User_id', referencedColumnName: 'id')]
|
||||
#[InverseJoinColumn(name: 'Group_id', referencedColumnName: 'id')]
|
||||
#[JoinColumn(name: 'user_id', referencedColumnName: 'id')]
|
||||
#[InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')]
|
||||
#[ManyToMany(targetEntity: Group::class)]
|
||||
private Collection $groups;
|
||||
// ...
|
||||
@@ -1333,10 +1333,10 @@ This is essentially the same as the following, more verbose, mapping:
|
||||
<many-to-many field="groups" target-entity="Group">
|
||||
<join-table name="User_Group">
|
||||
<join-columns>
|
||||
<join-column id="User_id" referenced-column-name="id" />
|
||||
<join-column id="user_id" referenced-column-name="id" />
|
||||
</join-columns>
|
||||
<inverse-join-columns>
|
||||
<join-column id="Group_id" referenced-column-name="id" />
|
||||
<join-column id="group_id" referenced-column-name="id" />
|
||||
</inverse-join-columns>
|
||||
</join-table>
|
||||
</many-to-many>
|
||||
|
||||
@@ -14,7 +14,7 @@ Index
|
||||
- :ref:`#[AttributeOverride] <attrref_attributeoverride>`
|
||||
- :ref:`#[Column] <attrref_column>`
|
||||
- :ref:`#[Cache] <attrref_cache>`
|
||||
- :ref:`#[ChangeTrackingPolicy <attrref_changetrackingpolicy>`
|
||||
- :ref:`#[ChangeTrackingPolicy] <attrref_changetrackingpolicy>`
|
||||
- :ref:`#[CustomIdGenerator] <attrref_customidgenerator>`
|
||||
- :ref:`#[DiscriminatorColumn] <attrref_discriminatorcolumn>`
|
||||
- :ref:`#[DiscriminatorMap] <attrref_discriminatormap>`
|
||||
|
||||
@@ -300,50 +300,12 @@ and a custom ``Doctrine\ORM\Mapping\TypedFieldMapper`` implementation.
|
||||
Doctrine Mapping Types
|
||||
----------------------
|
||||
|
||||
The ``type`` option used in the ``@Column`` accepts any of the existing
|
||||
Doctrine types or even your own custom types. A Doctrine type defines
|
||||
The ``type`` option used in the ``@Column`` accepts any of the
|
||||
`existing Doctrine DBAL types <https://docs.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/types.html#reference>`_
|
||||
or :doc:`your own custom mapping types
|
||||
<../cookbook/custom-mapping-types>`. A Doctrine type defines
|
||||
the conversion between PHP and SQL types, independent from the database vendor
|
||||
you are using. All Mapping Types that ship with Doctrine are fully portable
|
||||
between the supported database systems.
|
||||
|
||||
As an example, the Doctrine Mapping Type ``string`` defines the
|
||||
mapping from a PHP string to a SQL VARCHAR (or VARCHAR2 etc.
|
||||
depending on the RDBMS brand). Here is a quick overview of the
|
||||
built-in mapping types:
|
||||
|
||||
- ``string``: Type that maps a SQL VARCHAR to a PHP string.
|
||||
- ``integer``: Type that maps a SQL INT to a PHP integer.
|
||||
- ``smallint``: Type that maps a database SMALLINT to a PHP
|
||||
integer.
|
||||
- ``bigint``: Type that maps a database BIGINT to a PHP string.
|
||||
- ``boolean``: Type that maps a SQL boolean or equivalent (TINYINT) to a PHP boolean.
|
||||
- ``decimal``: Type that maps a SQL DECIMAL to a PHP string.
|
||||
- ``date``: Type that maps a SQL DATETIME to a PHP DateTime
|
||||
object.
|
||||
- ``time``: Type that maps a SQL TIME to a PHP DateTime object.
|
||||
- ``datetime``: Type that maps a SQL DATETIME/TIMESTAMP to a PHP
|
||||
DateTime object.
|
||||
- ``datetimetz``: Type that maps a SQL DATETIME/TIMESTAMP to a PHP
|
||||
DateTime object with timezone.
|
||||
- ``text``: Type that maps a SQL CLOB to a PHP string.
|
||||
- ``object``: Type that maps a SQL CLOB to a PHP object using
|
||||
``serialize()`` and ``unserialize()``
|
||||
- ``array``: Type that maps a SQL CLOB to a PHP array using
|
||||
``serialize()`` and ``unserialize()``
|
||||
- ``simple_array``: Type that maps a SQL CLOB to a PHP array using
|
||||
``implode()`` and ``explode()``, with a comma as delimiter. *IMPORTANT*
|
||||
Only use this type if you are sure that your values cannot contain a ",".
|
||||
- ``json_array``: Type that maps a SQL CLOB to a PHP array using
|
||||
``json_encode()`` and ``json_decode()``
|
||||
- ``float``: Type that maps a SQL Float (Double Precision) to a
|
||||
PHP double. *IMPORTANT*: Works only with locale settings that use
|
||||
decimal points as separator.
|
||||
- ``guid``: Type that maps a database GUID/UUID to a PHP string. Defaults to
|
||||
varchar but uses a specific type if the platform supports it.
|
||||
- ``blob``: Type that maps a SQL BLOB to a PHP resource stream
|
||||
|
||||
A cookbook article shows how to define :doc:`your own custom mapping types
|
||||
<../cookbook/custom-mapping-types>`.
|
||||
you are using.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -462,7 +424,7 @@ Here is the list of possible generation strategies:
|
||||
a new entity is passed to ``EntityManager#persist``. NONE is the
|
||||
same as leaving off the ``#[GeneratedValue]`` entirely.
|
||||
- ``CUSTOM``: With this option, you can use the ``#[CustomIdGenerator]`` attribute.
|
||||
It will allow you to pass a :ref:`class of your own to generate the identifiers.<annref_customidgenerator>`
|
||||
It will allow you to pass a :ref:`class of your own to generate the identifiers. <annref_customidgenerator>`
|
||||
|
||||
Sequence Generator
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -18,14 +18,20 @@ especially what the strategies presented here provide help with.
|
||||
|
||||
.. note::
|
||||
|
||||
Having an SQL logger enabled when processing batches can have a serious impact on performance and resource usage.
|
||||
To avoid that you should remove the corresponding middleware.
|
||||
To remove all middlewares, you can use this line:
|
||||
Having an SQL logger enabled when processing batches can have a
|
||||
serious impact on performance and resource usage.
|
||||
To avoid that, you should use a PSR logger implementation that can be
|
||||
disabled at runtime.
|
||||
For example, with Monolog, you can use ``Logger::pushHandler()``
|
||||
to push a ``NullHandler`` to the logger instance, and then pop it
|
||||
when you need to enable logging again.
|
||||
|
||||
With DBAL 2, you can disable the SQL logger like below:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$em->getConnection()->getConfiguration()->setMiddlewares([]); // DBAL 3
|
||||
$em->getConnection()->getConfiguration()->setSQLLogger(null); // DBAL 2
|
||||
$em->getConnection()->getConfiguration()->setSQLLogger(null);
|
||||
|
||||
Bulk Inserts
|
||||
------------
|
||||
@@ -188,6 +194,3 @@ problems using the following approach:
|
||||
Iterating results is not possible with queries that
|
||||
fetch-join a collection-valued association. The nature of such SQL
|
||||
result sets is not suitable for incremental hydration.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -812,7 +812,7 @@ classes have to implement the base class :
|
||||
namespace MyProject\Query\AST;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
class MysqlFloor extends FunctionNode
|
||||
{
|
||||
@@ -827,12 +827,12 @@ classes have to implement the base class :
|
||||
|
||||
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1003,7 +1003,7 @@ The Query class
|
||||
---------------
|
||||
|
||||
An instance of the ``Doctrine\ORM\Query`` class represents a DQL
|
||||
query. You create a Query instance be calling
|
||||
query. You create a Query instance by calling
|
||||
``EntityManager#createQuery($dql)``, passing the DQL query string.
|
||||
Alternatively you can create an empty ``Query`` instance and invoke
|
||||
``Query#setDQL($dql)`` afterwards. Here are some examples:
|
||||
@@ -1020,58 +1020,146 @@ Alternatively you can create an empty ``Query`` instance and invoke
|
||||
$q = $em->createQuery();
|
||||
$q->setDQL('select u from MyProject\Model\User u');
|
||||
|
||||
Query Result Formats
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
Query Result Formats (Hydration Modes)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The format in which the result of a DQL SELECT query is returned
|
||||
can be influenced by a so-called ``hydration mode``. A hydration
|
||||
mode specifies a particular way in which a SQL result set is
|
||||
transformed. Each hydration mode has its own dedicated method on
|
||||
the Query class. Here they are:
|
||||
The way in which the SQL result set of a DQL SELECT query is transformed
|
||||
to PHP is determined by the so-called "hydration mode".
|
||||
|
||||
``getResult()``
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
- ``Query#getResult()``: Retrieves a collection of objects. The
|
||||
result is either a plain collection of objects (pure) or an array
|
||||
where the objects are nested in the result rows (mixed).
|
||||
- ``Query#getSingleResult()``: Retrieves a single object. If the
|
||||
result contains more than one object, an ``NonUniqueResultException``
|
||||
is thrown. If the result contains no objects, an ``NoResultException``
|
||||
is thrown. The pure/mixed distinction does not apply.
|
||||
- ``Query#getOneOrNullResult()``: Retrieve a single object. If the
|
||||
result contains more than one object, a ``NonUniqueResultException``
|
||||
is thrown. If no object is found null will be returned.
|
||||
- ``Query#getArrayResult()``: Retrieves an array graph (a nested
|
||||
array) that is largely interchangeable with the object graph
|
||||
generated by ``Query#getResult()`` for read-only purposes.
|
||||
Retrieves a collection of objects. The result is either a plain collection of objects (pure) or an array
|
||||
where the objects are nested in the result rows (mixed):
|
||||
|
||||
.. note::
|
||||
.. code-block:: php
|
||||
|
||||
An array graph can differ from the corresponding object
|
||||
graph in certain scenarios due to the difference of the identity
|
||||
semantics between arrays and objects.
|
||||
<?php
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
|
||||
$query = $em->createQuery('SELECT u FROM User u');
|
||||
$users = $query->getResult();
|
||||
// same as:
|
||||
$users = $query->getResult(AbstractQuery::HYDRATE_OBJECT);
|
||||
|
||||
- Objects fetched in a FROM clause are returned as a Set, that means every
|
||||
object is only ever included in the resulting array once. This is the case
|
||||
even when using JOIN or GROUP BY in ways that return the same row for an
|
||||
object multiple times. If the hydrator sees the same object multiple times,
|
||||
then it makes sure it is only returned once.
|
||||
|
||||
- ``Query#getScalarResult()``: Retrieves a flat/rectangular result
|
||||
set of scalar values that can contain duplicate data. The
|
||||
pure/mixed distinction does not apply.
|
||||
- ``Query#getSingleScalarResult()``: Retrieves a single scalar
|
||||
value from the result returned by the dbms. If the result contains
|
||||
more than a single scalar value, an exception is thrown. The
|
||||
pure/mixed distinction does not apply.
|
||||
- If an object is already in memory from a previous query of any kind, then
|
||||
then the previous object is used, even if the database may contain more
|
||||
recent data. This even happens if the previous object is still an unloaded proxy.
|
||||
|
||||
Instead of using these methods, you can alternatively use the
|
||||
general-purpose method
|
||||
``Query#execute(array $params = [], $hydrationMode = Query::HYDRATE_OBJECT)``.
|
||||
Using this method you can directly supply the hydration mode as the
|
||||
second parameter via one of the Query constants. In fact, the
|
||||
methods mentioned earlier are just convenient shortcuts for the
|
||||
execute method. For example, the method ``Query#getResult()``
|
||||
internally invokes execute, passing in ``Query::HYDRATE_OBJECT`` as
|
||||
the hydration mode.
|
||||
``getArrayResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The use of the methods mentioned earlier is generally preferred as
|
||||
it leads to more concise code.
|
||||
Retrieves an array graph (a nested array) for read-only purposes.
|
||||
|
||||
.. note::
|
||||
|
||||
An array graph can differ from the corresponding object
|
||||
graph in certain scenarios due to the difference of the identity
|
||||
semantics between arrays and objects.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$users = $query->getArrayResult();
|
||||
// same as:
|
||||
$users = $query->getResult(AbstractQuery::HYDRATE_ARRAY);
|
||||
|
||||
``getScalarResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieves a flat/rectangular result set of scalar values that can contain duplicate data. The
|
||||
pure/mixed distinction does not apply.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$users = $query->getScalarResult();
|
||||
// same as:
|
||||
$users = $query->getResult(AbstractQuery::HYDRATE_SCALAR);
|
||||
|
||||
Fields from classes are prefixed by the DQL alias in the result.
|
||||
A query of the kind `SELECT u.name ...` returns a key `u_name` in the result rows.
|
||||
|
||||
``getSingleScalarResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieves a single scalar value from the result returned by the database. If the result contains
|
||||
more than a single scalar value, a ``NonUniqueResultException`` is thrown. The pure/mixed distinction does not apply.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT COUNT(u.id) FROM User u');
|
||||
$numUsers = $query->getSingleScalarResult();
|
||||
// same as:
|
||||
$numUsers = $query->getResult(AbstractQuery::HYDRATE_SINGLE_SCALAR);
|
||||
|
||||
``getSingleColumnResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieves an array from a one-dimensional array of scalar values:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT a.id FROM User u');
|
||||
$ids = $query->getSingleColumnResult();
|
||||
// same as:
|
||||
$ids = $query->getResult(AbstractQuery::HYDRATE_SCALAR_COLUMN);
|
||||
|
||||
``getSingleResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieves a single object. If the result contains more than one object, a ``NonUniqueResultException``
|
||||
is thrown. If the result contains no objects, a ``NoResultException`` is thrown. The pure/mixed distinction does not apply.
|
||||
|
||||
``getOneOrNullResult()``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Retrieves a single object. If the result contains more than one object, a ``NonUniqueResultException``
|
||||
is thrown. If no object is found, ``null`` will be returned.
|
||||
|
||||
Custom Hydration Modes
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can easily add your own custom hydration modes by first
|
||||
creating a class which extends ``AbstractHydrator``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace MyProject\Hydrators;
|
||||
|
||||
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
|
||||
|
||||
class CustomHydrator extends AbstractHydrator
|
||||
{
|
||||
protected function _hydrateAll()
|
||||
{
|
||||
return $this->_stmt->fetchAllAssociative();
|
||||
}
|
||||
}
|
||||
|
||||
Next you just need to add the class to the ORM configuration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$em->getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator');
|
||||
|
||||
Now the hydrator is ready to be used in your queries:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u');
|
||||
$results = $query->getResult('CustomHydrator');
|
||||
|
||||
Pure and Mixed Results
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -1175,165 +1263,6 @@ will return the rows iterating the different top-level entities.
|
||||
[2] => Object (User)
|
||||
[3] => Object (Group)
|
||||
|
||||
|
||||
Hydration Modes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Each of the Hydration Modes makes assumptions about how the result
|
||||
is returned to user land. You should know about all the details to
|
||||
make best use of the different result formats:
|
||||
|
||||
The constants for the different hydration modes are:
|
||||
|
||||
|
||||
- ``Query::HYDRATE_OBJECT``
|
||||
- ``Query::HYDRATE_ARRAY``
|
||||
- ``Query::HYDRATE_SCALAR``
|
||||
- ``Query::HYDRATE_SINGLE_SCALAR``
|
||||
- ``Query::HYDRATE_SCALAR_COLUMN``
|
||||
|
||||
Object Hydration
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Object hydration hydrates the result set into the object graph:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u');
|
||||
$users = $query->getResult(Query::HYDRATE_OBJECT);
|
||||
|
||||
Sometimes the behavior in the object hydrator can be confusing, which is
|
||||
why we are listing as many of the assumptions here for reference:
|
||||
|
||||
- Objects fetched in a FROM clause are returned as a Set, that means every
|
||||
object is only ever included in the resulting array once. This is the case
|
||||
even when using JOIN or GROUP BY in ways that return the same row for an
|
||||
object multiple times. If the hydrator sees the same object multiple times,
|
||||
then it makes sure it is only returned once.
|
||||
|
||||
- If an object is already in memory from a previous query of any kind, then
|
||||
then the previous object is used, even if the database may contain more
|
||||
recent data. Data from the database is discarded. This even happens if the
|
||||
previous object is still an unloaded proxy.
|
||||
|
||||
This list might be incomplete.
|
||||
|
||||
Array Hydration
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
You can run the same query with array hydration and the result set
|
||||
is hydrated into an array that represents the object graph:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u');
|
||||
$users = $query->getResult(Query::HYDRATE_ARRAY);
|
||||
|
||||
You can use the ``getArrayResult()`` shortcut as well:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$users = $query->getArrayResult();
|
||||
|
||||
Scalar Hydration
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
If you want to return a flat rectangular result set instead of an
|
||||
object graph you can use scalar hydration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u');
|
||||
$users = $query->getResult(Query::HYDRATE_SCALAR);
|
||||
echo $users[0]['u_id'];
|
||||
|
||||
The following assumptions are made about selected fields using
|
||||
Scalar Hydration:
|
||||
|
||||
|
||||
1. Fields from classes are prefixed by the DQL alias in the result.
|
||||
A query of the kind 'SELECT u.name ..' returns a key 'u_name' in
|
||||
the result rows.
|
||||
|
||||
Single Scalar Hydration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you have a query which returns just a single scalar value you can use
|
||||
single scalar hydration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT COUNT(a.id) FROM CmsUser u LEFT JOIN u.articles a WHERE u.username = ?1 GROUP BY u.id');
|
||||
$query->setParameter(1, 'jwage');
|
||||
$numArticles = $query->getResult(Query::HYDRATE_SINGLE_SCALAR);
|
||||
|
||||
You can use the ``getSingleScalarResult()`` shortcut as well:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$numArticles = $query->getSingleScalarResult();
|
||||
|
||||
Scalar Column Hydration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you have a query which returns a one-dimensional array of scalar values
|
||||
you can use scalar column hydration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT a.id FROM CmsUser u');
|
||||
$ids = $query->getResult(Query::HYDRATE_SCALAR_COLUMN);
|
||||
|
||||
You can use the ``getSingleColumnResult()`` shortcut as well:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$ids = $query->getSingleColumnResult();
|
||||
|
||||
Custom Hydration Modes
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can easily add your own custom hydration modes by first
|
||||
creating a class which extends ``AbstractHydrator``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
namespace MyProject\Hydrators;
|
||||
|
||||
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
|
||||
|
||||
class CustomHydrator extends AbstractHydrator
|
||||
{
|
||||
protected function _hydrateAll()
|
||||
{
|
||||
return $this->_stmt->fetchAllAssociative();
|
||||
}
|
||||
}
|
||||
|
||||
Next you just need to add the class to the ORM configuration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$em->getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator');
|
||||
|
||||
Now the hydrator is ready to be used in your queries:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$query = $em->createQuery('SELECT u FROM CmsUser u');
|
||||
$results = $query->getResult('CustomHydrator');
|
||||
|
||||
Iterating Large Result Sets
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -131,47 +131,47 @@ There are two ways to set up an event handler:
|
||||
* For *all events* you can create a Lifecycle Event Listener or Subscriber class and register
|
||||
it by calling ``$eventManager->addEventListener()`` or ``eventManager->addEventSubscriber()``,
|
||||
see
|
||||
:ref:`Listening and subscribing to Lifecycle Events<listening-and-subscribing-to-lifecycle-events>`
|
||||
:ref:`Listening and subscribing to Lifecycle Events <listening-and-subscribing-to-lifecycle-events>`
|
||||
* For *some events* (see table below), you can create a *Lifecycle Callback* method in the
|
||||
entity, see :ref:`Lifecycle Callbacks<lifecycle-callbacks>`.
|
||||
entity, see :ref:`Lifecycle Callbacks <lifecycle-callbacks>`.
|
||||
|
||||
.. _reference-events-lifecycle-events:
|
||||
|
||||
Events Overview
|
||||
---------------
|
||||
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| Event | Dispatched by | Lifecycle | Passed |
|
||||
| | | Callback | Argument |
|
||||
+=================================================================+=======================+===========+=====================================+
|
||||
| :ref:`preRemove<reference-events-pre-remove>` | ``$em->remove()`` | Yes | `PreRemoveEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postRemove<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostRemoveEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`prePersist<reference-events-pre-persist>` | ``$em->persist()`` | Yes | `PrePersistEventArgs`_ |
|
||||
| | on *initial* persist | | |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postPersist<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostPersistEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preUpdate<reference-events-pre-update>` | ``$em->flush()`` | Yes | `PreUpdateEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postUpdate<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostUpdateEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postLoad<reference-events-post-load>` | Loading from database | Yes | `PostLoadEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`loadClassMetadata<reference-events-load-class-metadata>` | Loading of mapping | No | `LoadClassMetadataEventArgs`_ |
|
||||
| | metadata | | |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| ``onClassMetadataNotFound`` | ``MappingException`` | No | `OnClassMetadataNotFoundEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preFlush<reference-events-pre-flush>` | ``$em->flush()`` | Yes | `PreFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onFlush<reference-events-on-flush>` | ``$em->flush()`` | No | `OnFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postFlush<reference-events-post-flush>` | ``$em->flush()`` | No | `PostFlushEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onClear<reference-events-on-clear>` | ``$em->clear()`` | No | `OnClearEventArgs`_ |
|
||||
+-----------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| Event | Dispatched by | Lifecycle | Passed |
|
||||
| | | Callback | Argument |
|
||||
+==================================================================+=======================+===========+=====================================+
|
||||
| :ref:`preRemove <reference-events-pre-remove>` | ``$em->remove()`` | Yes | `PreRemoveEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postRemove <reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostRemoveEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`prePersist <reference-events-pre-persist>` | ``$em->persist()`` | Yes | `PrePersistEventArgs`_ |
|
||||
| | on *initial* persist | | |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postPersist <reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostPersistEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preUpdate <reference-events-pre-update>` | ``$em->flush()`` | Yes | `PreUpdateEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postUpdate <reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes | `PostUpdateEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postLoad <reference-events-post-load>` | Loading from database | Yes | `PostLoadEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`loadClassMetadata <reference-events-load-class-metadata>` | Loading of mapping | No | `LoadClassMetadataEventArgs`_ |
|
||||
| | metadata | | |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| ``onClassMetadataNotFound`` | ``MappingException`` | No | `OnClassMetadataNotFoundEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`preFlush <reference-events-pre-flush>` | ``$em->flush()`` | Yes | `PreFlushEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onFlush <reference-events-on-flush>` | ``$em->flush()`` | No | `OnFlushEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`postFlush <reference-events-post-flush>` | ``$em->flush()`` | No | `PostFlushEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
| :ref:`onClear <reference-events-on-clear>` | ``$em->clear()`` | No | `OnClearEventArgs`_ |
|
||||
+------------------------------------------------------------------+-----------------------+-----------+-------------------------------------+
|
||||
|
||||
.. warning::
|
||||
|
||||
@@ -358,7 +358,7 @@ behaviors across different entity classes.
|
||||
|
||||
Note that they require much more detailed knowledge about the inner
|
||||
workings of the ``EntityManager`` and ``UnitOfWork`` classes. Please
|
||||
read the :ref:`Implementing Event Listeners<reference-events-implementing-listeners>` section
|
||||
read the :ref:`Implementing Event Listeners <reference-events-implementing-listeners>` section
|
||||
carefully if you are trying to write your own listener.
|
||||
|
||||
For event subscribers, there are no surprises. They declare the
|
||||
@@ -471,11 +471,11 @@ prePersist
|
||||
There are two ways for the ``prePersist`` event to be triggered:
|
||||
|
||||
- One is when you call ``EntityManager::persist()``. The
|
||||
event is also called for all :ref:`cascaded associations<transitive-persistence>`.
|
||||
event is also called for all :ref:`cascaded associations <transitive-persistence>`.
|
||||
- The other is inside the ``flush()`` method when changes to associations are computed and
|
||||
this association is marked as :ref:`cascade: persist<transitive-persistence>`. Any new entity found
|
||||
this association is marked as :ref:`cascade: persist <transitive-persistence>`. Any new entity found
|
||||
during this operation is also persisted and ``prePersist`` called
|
||||
on it. This is called :ref:`persistence by reachability<persistence-by-reachability>`.
|
||||
on it. This is called :ref:`persistence by reachability <persistence-by-reachability>`.
|
||||
|
||||
In both cases you get passed a ``PrePersistEventArgs`` instance
|
||||
which has access to the entity and the entity manager.
|
||||
@@ -499,7 +499,7 @@ preRemove
|
||||
|
||||
The ``preRemove`` event is called on every entity immediately when it is passed
|
||||
to the ``EntityManager::remove()`` method. It is cascaded for all
|
||||
associations that are marked as :ref:`cascade: remove<transitive-persistence>`
|
||||
associations that are marked as :ref:`cascade: remove <transitive-persistence>`
|
||||
|
||||
It is not called for a DQL ``DELETE`` statement.
|
||||
|
||||
@@ -547,7 +547,7 @@ entities and their associations have been computed. This means, the
|
||||
- Collections scheduled for removal
|
||||
|
||||
To make use of the ``onFlush`` event you have to be familiar with the
|
||||
internal :ref:`UnitOfWork<unit-of-work>` API, which grants you access to the previously
|
||||
internal :ref:`UnitOfWork <unit-of-work>` API, which grants you access to the previously
|
||||
mentioned sets. See this example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@@ -101,7 +101,7 @@ The many-to-many association is only supporting foreign keys in the table defini
|
||||
To work with many-to-many tables containing extra columns you have to use the
|
||||
foreign keys as primary keys feature of Doctrine ORM.
|
||||
|
||||
See :doc:`the tutorial on composite primary keys for more information<../tutorials/composite-primary-keys>`.
|
||||
See :doc:`the tutorial on composite primary keys for more information <../tutorials/composite-primary-keys>`.
|
||||
|
||||
|
||||
How can i paginate fetch-joined collections?
|
||||
|
||||
@@ -380,7 +380,7 @@ It is not supported to use overrides in entity inheritance scenarios.
|
||||
.. note::
|
||||
|
||||
When using traits, make sure not to miss the warnings given in the
|
||||
:doc:`Limitations and Known Issues</reference/limitations-and-known-issues>` chapter.
|
||||
:doc:`Limitations and Known Issues </reference/limitations-and-known-issues>` chapter.
|
||||
|
||||
|
||||
Association Override
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
:orphan:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
|
||||
@@ -81,8 +81,8 @@ implements the ``MappingDriver`` interface:
|
||||
/**
|
||||
* Loads the metadata for the specified class into the provided container.
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -93,8 +93,7 @@ implements the ``MappingDriver`` interface:
|
||||
/**
|
||||
* Gets the names of all mapped classes known to this driver.
|
||||
*
|
||||
* @return array<int, string> The names of all mapped classes known to this driver.
|
||||
* @psalm-return list<class-string>
|
||||
* @return list<class-string> The names of all mapped classes known to this driver.
|
||||
*/
|
||||
public function getAllClassNames();
|
||||
|
||||
@@ -102,7 +101,7 @@ implements the ``MappingDriver`` interface:
|
||||
* Returns whether the class with the specified name should have its metadata loaded.
|
||||
* This is only the case if it is either mapped as an Entity or a MappedSuperclass.
|
||||
*
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -88,7 +88,7 @@ requirement.
|
||||
|
||||
A more convenient alternative for explicit transaction demarcation is the use
|
||||
of provided control abstractions in the form of
|
||||
``Connection#transactional($func)`` and ``EntityManager#transactional($func)``.
|
||||
``Connection#transactional($func)`` and ``EntityManager#wrapInTransaction($func)``.
|
||||
When used, these control abstractions ensure that you never forget to rollback
|
||||
the transaction, in addition to the obvious code reduction. An example that is
|
||||
functionally equivalent to the previously shown code looks as follows:
|
||||
@@ -96,21 +96,23 @@ functionally equivalent to the previously shown code looks as follows:
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// transactional with Connection instance
|
||||
// $conn instanceof Connection
|
||||
$conn->transactional(function($conn) {
|
||||
// ... do some work
|
||||
$user = new User;
|
||||
$user->setName('George');
|
||||
});
|
||||
|
||||
// transactional with EntityManager instance
|
||||
// $em instanceof EntityManager
|
||||
$em->transactional(function($em) {
|
||||
$em->wrapInTransaction(function($em) {
|
||||
// ... do some work
|
||||
$user = new User;
|
||||
$user->setName('George');
|
||||
$em->persist($user);
|
||||
});
|
||||
|
||||
.. warning::
|
||||
|
||||
For historical reasons, ``EntityManager#transactional($func)`` will return
|
||||
``true`` whenever the return value of ``$func`` is loosely false.
|
||||
Some examples of this include ``array()``, ``"0"``, ``""``, ``0``, and
|
||||
``null``.
|
||||
|
||||
The difference between ``Connection#transactional($func)`` and
|
||||
``EntityManager#transactional($func)`` is that the latter
|
||||
abstraction flushes the ``EntityManager`` prior to transaction
|
||||
|
||||
@@ -338,10 +338,11 @@ Performance of different deletion strategies
|
||||
Deleting an object with all its associated objects can be achieved
|
||||
in multiple ways with very different performance impacts.
|
||||
|
||||
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM
|
||||
will fetch this association. If its a Single association it will
|
||||
pass this entity to
|
||||
``EntityManager#remove()``. If the association is a collection, Doctrine will loop over all its elements and pass them to``EntityManager#remove()``.
|
||||
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM will
|
||||
fetch this association. If it's a Single association it will pass
|
||||
this entity to ``EntityManager#remove()``. If the association is a
|
||||
collection, Doctrine will loop over all its elements and pass them to
|
||||
``EntityManager#remove()``.
|
||||
In both cases the cascade remove semantics are applied recursively.
|
||||
For large object graphs this removal strategy can be very costly.
|
||||
2. Using a DQL ``DELETE`` statement allows you to delete multiple
|
||||
|
||||
+71
-77
@@ -1,83 +1,77 @@
|
||||
.. toc::
|
||||
:orphan:
|
||||
|
||||
.. tocheader:: Tutorials
|
||||
.. toctree::
|
||||
:caption: Tutorials
|
||||
:depth: 3
|
||||
|
||||
.. toctree::
|
||||
:depth: 3
|
||||
tutorials/getting-started
|
||||
tutorials/getting-started-database
|
||||
tutorials/getting-started-models
|
||||
tutorials/working-with-indexed-associations
|
||||
tutorials/extra-lazy-associations
|
||||
tutorials/composite-primary-keys
|
||||
tutorials/ordered-associations
|
||||
tutorials/override-field-association-mappings-in-subclasses
|
||||
tutorials/pagination
|
||||
tutorials/embeddables
|
||||
|
||||
tutorials/getting-started
|
||||
tutorials/getting-started-database
|
||||
tutorials/getting-started-models
|
||||
tutorials/working-with-indexed-associations
|
||||
tutorials/extra-lazy-associations
|
||||
tutorials/composite-primary-keys
|
||||
tutorials/ordered-associations
|
||||
tutorials/override-field-association-mappings-in-subclasses
|
||||
tutorials/pagination
|
||||
tutorials/embeddables
|
||||
.. toctree::
|
||||
:caption: Reference
|
||||
:depth: 3
|
||||
|
||||
.. toc::
|
||||
reference/architecture
|
||||
reference/configuration
|
||||
reference/faq
|
||||
reference/basic-mapping
|
||||
reference/association-mapping
|
||||
reference/inheritance-mapping
|
||||
reference/working-with-objects
|
||||
reference/working-with-associations
|
||||
reference/typedfieldmapper
|
||||
reference/events
|
||||
reference/unitofwork
|
||||
reference/unitofwork-associations
|
||||
reference/transactions-and-concurrency
|
||||
reference/batch-processing
|
||||
reference/dql-doctrine-query-language
|
||||
reference/query-builder
|
||||
reference/native-sql
|
||||
reference/change-tracking-policies
|
||||
reference/partial-objects
|
||||
reference/annotations-reference
|
||||
reference/attributes-reference
|
||||
reference/xml-mapping
|
||||
reference/yaml-mapping
|
||||
reference/php-mapping
|
||||
reference/caching
|
||||
reference/improving-performance
|
||||
reference/tools
|
||||
reference/metadata-drivers
|
||||
reference/best-practices
|
||||
reference/limitations-and-known-issues
|
||||
tutorials/pagination
|
||||
reference/filters
|
||||
reference/namingstrategy
|
||||
reference/advanced-configuration
|
||||
reference/second-level-cache
|
||||
reference/security
|
||||
|
||||
.. tocheader:: Reference
|
||||
.. toctree::
|
||||
:caption: Cookbook
|
||||
:depth: 3
|
||||
|
||||
.. toctree::
|
||||
:depth: 3
|
||||
|
||||
reference/architecture
|
||||
reference/configuration
|
||||
reference/faq
|
||||
reference/basic-mapping
|
||||
reference/association-mapping
|
||||
reference/inheritance-mapping
|
||||
reference/working-with-objects
|
||||
reference/working-with-associations
|
||||
reference/events
|
||||
reference/unitofwork
|
||||
reference/unitofwork-associations
|
||||
reference/transactions-and-concurrency
|
||||
reference/batch-processing
|
||||
reference/dql-doctrine-query-language
|
||||
reference/query-builder
|
||||
reference/native-sql
|
||||
reference/change-tracking-policies
|
||||
reference/partial-objects
|
||||
reference/annotations-reference
|
||||
reference/attributes-reference
|
||||
reference/xml-mapping
|
||||
reference/yaml-mapping
|
||||
reference/php-mapping
|
||||
reference/caching
|
||||
reference/improving-performance
|
||||
reference/tools
|
||||
reference/metadata-drivers
|
||||
reference/best-practices
|
||||
reference/limitations-and-known-issues
|
||||
tutorials/pagination
|
||||
reference/filters
|
||||
reference/namingstrategy
|
||||
reference/advanced-configuration
|
||||
reference/second-level-cache
|
||||
reference/security
|
||||
|
||||
.. toc::
|
||||
|
||||
.. tocheader:: Cookbook
|
||||
|
||||
.. toctree::
|
||||
:depth: 3
|
||||
|
||||
cookbook/aggregate-fields
|
||||
cookbook/custom-mapping-types
|
||||
cookbook/decorator-pattern
|
||||
cookbook/dql-custom-walkers
|
||||
cookbook/dql-user-defined-functions
|
||||
cookbook/implementing-arrayaccess-for-domain-objects
|
||||
cookbook/implementing-the-notify-changetracking-policy
|
||||
cookbook/resolve-target-entity-listener
|
||||
cookbook/sql-table-prefixes
|
||||
cookbook/strategy-cookbook-introduction
|
||||
cookbook/validation-of-entities
|
||||
cookbook/working-with-datetime
|
||||
cookbook/mysql-enums
|
||||
cookbook/advanced-field-value-conversion-using-custom-mapping-types
|
||||
cookbook/entities-in-session
|
||||
cookbook/aggregate-fields
|
||||
cookbook/custom-mapping-types
|
||||
cookbook/decorator-pattern
|
||||
cookbook/dql-custom-walkers
|
||||
cookbook/dql-user-defined-functions
|
||||
cookbook/implementing-arrayaccess-for-domain-objects
|
||||
cookbook/implementing-the-notify-changetracking-policy
|
||||
cookbook/resolve-target-entity-listener
|
||||
cookbook/sql-table-prefixes
|
||||
cookbook/strategy-cookbook-introduction
|
||||
cookbook/validation-of-entities
|
||||
cookbook/working-with-datetime
|
||||
cookbook/mysql-enums
|
||||
cookbook/advanced-field-value-conversion-using-custom-mapping-types
|
||||
cookbook/entities-in-session
|
||||
|
||||
@@ -188,7 +188,7 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
|
||||
#[OneToMany(targetEntity: ArticleAttribute::class, mappedBy: 'article', cascade: ['ALL'], indexBy: 'attribute')]
|
||||
private Collection $attributes;
|
||||
|
||||
public function addAttribute(string $name, ArticleAttribute $value): void
|
||||
public function addAttribute(string $name, string $value): void
|
||||
{
|
||||
$this->attributes[$name] = new ArticleAttribute($name, $value, $this);
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ step:
|
||||
|
||||
// Create a simple "default" Doctrine ORM configuration for Attributes
|
||||
$config = ORMSetup::createAttributeMetadataConfiguration(
|
||||
paths: array(__DIR__."/src"),
|
||||
paths: [__DIR__ . '/src'],
|
||||
isDevMode: true,
|
||||
);
|
||||
// or if you prefer annotation, YAML or XML
|
||||
@@ -153,7 +153,7 @@ step:
|
||||
// isDevMode: true,
|
||||
// );
|
||||
// $config = ORMSetup::createXMLMetadataConfiguration(
|
||||
// paths: array(__DIR__."/config/xml"),
|
||||
// paths: [__DIR__ . '/config/xml'],
|
||||
// isDevMode: true,
|
||||
//);
|
||||
// $config = ORMSetup::createYAMLMetadataConfiguration(
|
||||
|
||||
+5
-1
@@ -14,7 +14,6 @@
|
||||
<file>src</file>
|
||||
<file>tests</file>
|
||||
|
||||
<exclude-pattern>*/src/Mapping/InverseJoinColumn.php</exclude-pattern>
|
||||
<exclude-pattern>*/tests/Tests/Proxies/__CG__*</exclude-pattern>
|
||||
<exclude-pattern>*/tests/Tests/ORM/Tools/Export/export/*</exclude-pattern>
|
||||
|
||||
@@ -279,4 +278,9 @@
|
||||
<!-- https://github.com/doctrine/orm/issues/8537 -->
|
||||
<exclude-pattern>src/QueryBuilder.php</exclude-pattern>
|
||||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.PHP.UselessParentheses">
|
||||
<!-- We need those parentheses to make enum access seem like valid syntax on PHP 7 -->
|
||||
<exclude-pattern>src/Mapping/Driver/XmlDriver.php</exclude-pattern>
|
||||
</rule>
|
||||
</ruleset>
|
||||
|
||||
+4
-34
@@ -135,11 +135,6 @@ parameters:
|
||||
count: 2
|
||||
path: src/EntityManager.php
|
||||
|
||||
-
|
||||
message: "#^Template type T of method Doctrine\\\\ORM\\\\EntityManagerInterface\\:\\:getClassMetadata\\(\\) is not referenced in a parameter\\.$#"
|
||||
count: 1
|
||||
path: src/EntityManagerInterface.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\\>\\.$#"
|
||||
count: 1
|
||||
@@ -171,7 +166,7 @@ parameters:
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
-
|
||||
message: "#^Method Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo\\:\\:fullyQualifiedClassName\\(\\) should return class\\-string\\|null but returns string\\|null\\.$#"
|
||||
message: "#^Call to an undefined method ReflectionProperty\\:\\:getHooks\\(\\)\\.$#"
|
||||
count: 1
|
||||
path: src/Mapping/ClassMetadataInfo.php
|
||||
|
||||
@@ -236,7 +231,7 @@ parameters:
|
||||
path: src/Mapping/Driver/XmlDriver.php
|
||||
|
||||
-
|
||||
message: "#^Offset 'version' on \\*NEVER\\* in isset\\(\\) always exists and is always null\\.$#"
|
||||
message: "#^Offset 'version' on \\*NEVER\\* in isset\\(\\) always exists and is not nullable\\.$#"
|
||||
count: 1
|
||||
path: src/Mapping/Driver/XmlDriver.php
|
||||
|
||||
@@ -331,22 +326,7 @@ parameters:
|
||||
path: src/Query/AST/Functions/DateSubFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$simpleArithmeticExpr of method Doctrine\\\\ORM\\\\Query\\\\SqlWalker\\:\\:walkSimpleArithmeticExpression\\(\\) expects Doctrine\\\\ORM\\\\Query\\\\AST\\\\SimpleArithmeticExpression, Doctrine\\\\ORM\\\\Query\\\\AST\\\\Node given\\.$#"
|
||||
count: 1
|
||||
path: src/Query/AST/Functions/LengthFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$simpleArithmeticExpr of method Doctrine\\\\ORM\\\\Query\\\\SqlWalker\\:\\:walkSimpleArithmeticExpression\\(\\) expects Doctrine\\\\ORM\\\\Query\\\\AST\\\\SimpleArithmeticExpression, Doctrine\\\\ORM\\\\Query\\\\AST\\\\Node given\\.$#"
|
||||
count: 1
|
||||
path: src/Query/AST/Functions/LowerFunction.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$simpleArithmeticExpr of method Doctrine\\\\ORM\\\\Query\\\\SqlWalker\\:\\:walkSimpleArithmeticExpression\\(\\) expects Doctrine\\\\ORM\\\\Query\\\\AST\\\\SimpleArithmeticExpression, Doctrine\\\\ORM\\\\Query\\\\AST\\\\Node given\\.$#"
|
||||
count: 1
|
||||
path: src/Query/AST/Functions/UpperFunction.php
|
||||
|
||||
-
|
||||
message: "#^Method Doctrine\\\\ORM\\\\Query\\\\AST\\\\IndexBy\\:\\:dispatch\\(\\) should return string but returns void\\.$#"
|
||||
message: "#^Method Doctrine\\\\ORM\\\\Query\\\\AST\\\\IndexBy\\:\\:dispatch\\(\\) should return string but returns null\\.$#"
|
||||
count: 1
|
||||
path: src/Query/AST/IndexBy.php
|
||||
|
||||
@@ -395,11 +375,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Query/Expr/Select.php
|
||||
|
||||
-
|
||||
message: "#^Comparison operation \"\\<\" between null and 102 is always true\\.$#"
|
||||
count: 1
|
||||
path: src/Query/Parser.php
|
||||
|
||||
-
|
||||
message: "#^Method Doctrine\\\\ORM\\\\Query\\\\Parser\\:\\:ArithmeticFactor\\(\\) should return Doctrine\\\\ORM\\\\Query\\\\AST\\\\ArithmeticFactor but returns Doctrine\\\\ORM\\\\Query\\\\AST\\\\Node\\|string\\.$#"
|
||||
count: 1
|
||||
@@ -415,14 +390,9 @@ parameters:
|
||||
count: 1
|
||||
path: src/Query/Parser.php
|
||||
|
||||
-
|
||||
message: "#^Result of && is always true\\.$#"
|
||||
count: 1
|
||||
path: src/Query/Parser.php
|
||||
|
||||
-
|
||||
message: "#^Unreachable statement \\- code above always terminates\\.$#"
|
||||
count: 4
|
||||
count: 3
|
||||
path: src/Query/Parser.php
|
||||
|
||||
-
|
||||
|
||||
@@ -61,6 +61,11 @@ parameters:
|
||||
count: 2
|
||||
path: src/Mapping/ClassMetadataFactory.php
|
||||
|
||||
- '~^Call to deprecated method getSQLResultCasing\(\) of class Doctrine\\DBAL\\Platforms\\AbstractPlatform\.$~'
|
||||
-
|
||||
message: '~deprecated class Doctrine\\DBAL\\Tools\\Console\\Command\\ImportCommand\:~'
|
||||
path: src/Tools/Console/ConsoleRunner.php
|
||||
|
||||
# Symfony cache supports passing a key prefix to the clear method.
|
||||
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
|
||||
|
||||
@@ -74,3 +79,9 @@ parameters:
|
||||
-
|
||||
message: '#^Call to method injectObjectManager\(\) on an unknown class Doctrine\\Persistence\\ObjectManagerAware\.$#'
|
||||
path: src/UnitOfWork.php
|
||||
|
||||
-
|
||||
message: '#contains generic type.*but class.*is not generic#'
|
||||
paths:
|
||||
- src/Mapping/Driver/XmlDriver.php
|
||||
- src/Mapping/Driver/YamlDriver.php
|
||||
|
||||
@@ -3,6 +3,8 @@ includes:
|
||||
- phpstan-params.neon
|
||||
|
||||
parameters:
|
||||
reportUnmatchedIgnoredErrors: false
|
||||
|
||||
ignoreErrors:
|
||||
# deprecations from doctrine/dbal:3.x
|
||||
- '/^Call to an undefined method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getGuidExpression\(\).$/'
|
||||
@@ -31,6 +33,31 @@ parameters:
|
||||
message: '/^Instanceof between Doctrine\\DBAL\\Platforms\\AbstractPlatform and Doctrine\\DBAL\\Platforms\\MySQLPlatform will always evaluate to false\.$/'
|
||||
path: src/Utility/LockSqlHelper.php
|
||||
|
||||
# Forward compatibility with Collections 3
|
||||
-
|
||||
message: '#^Parameter \$order of anonymous function has invalid type Doctrine\\Common\\Collections\\Order\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
-
|
||||
message: '#^Anonymous function has invalid return type Doctrine\\Common\\Collections\\Order\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
-
|
||||
message: '#^Access to property \$value on an unknown class Doctrine\\Common\\Collections\\Order\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
-
|
||||
message: '#^Call to static method from\(\) on an unknown class Doctrine\\Common\\Collections\\Order\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Doctrine\\Common\\Collections\\Criteria\:\:orderings\(\)\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
-
|
||||
message: '#^Method .+\:\:mapToOrderEnumIfAvailable\(\) has invalid return type Doctrine\\Common\\Collections\\Order\.$#'
|
||||
path: src/Internal/CriteriaOrderings.php
|
||||
|
||||
# False positive
|
||||
-
|
||||
message: '/^Call to an undefined method Doctrine\\Common\\Cache\\Cache::deleteAll\(\)\.$/'
|
||||
@@ -39,3 +66,19 @@ parameters:
|
||||
|
||||
# Symfony cache supports passing a key prefix to the clear method.
|
||||
- '/^Method Psr\\Cache\\CacheItemPoolInterface\:\:clear\(\) invoked with 1 parameter, 0 required\.$/'
|
||||
|
||||
-
|
||||
message: '#contains generic type.*but class.*is not generic#'
|
||||
paths:
|
||||
- src/Mapping/Driver/XmlDriver.php
|
||||
- src/Mapping/Driver/YamlDriver.php
|
||||
|
||||
# Extending a deprecated class conditionally to maintain BC
|
||||
-
|
||||
message: '~deprecated class Doctrine\\Persistence\\Mapping\\Driver\\AnnotationDriver\:~'
|
||||
path: src/Mapping/Driver/CompatibilityAnnotationDriver.php
|
||||
|
||||
# We're sniffing for this deprecated class in order to detect Persistence 2
|
||||
-
|
||||
message: '~deprecated class Doctrine\\Common\\Persistence\\PersistentObject\:~'
|
||||
path: src/EntityManager.php
|
||||
|
||||
+858
-812
File diff suppressed because it is too large
Load Diff
@@ -243,6 +243,12 @@
|
||||
<file name="src/Mapping/ClassMetadataFactory.php"/>
|
||||
</errorLevel>
|
||||
</ReferenceConstraintViolation>
|
||||
<RiskyTruthyFalsyComparison>
|
||||
<!-- TODO: Enable this new rule on higher branches. -->
|
||||
<errorLevel type="suppress">
|
||||
<directory name="src" />
|
||||
</errorLevel>
|
||||
</RiskyTruthyFalsyComparison>
|
||||
<TooManyArguments>
|
||||
<errorLevel type="suppress">
|
||||
<!-- Symfony cache supports passing a key prefix to the clear method. -->
|
||||
|
||||
@@ -558,9 +558,11 @@ abstract class AbstractQuery
|
||||
|
||||
// DBAL 2
|
||||
if (! method_exists(QueryCacheProfile::class, 'setResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (! $profile->getResultCacheDriver()) {
|
||||
$defaultHydrationCacheImpl = $this->_em->getConfiguration()->getHydrationCache();
|
||||
if ($defaultHydrationCacheImpl) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$profile = $profile->setResultCacheDriver(DoctrineProvider::wrap($defaultHydrationCacheImpl));
|
||||
}
|
||||
}
|
||||
@@ -609,9 +611,11 @@ abstract class AbstractQuery
|
||||
|
||||
// DBAL 2
|
||||
if (! method_exists(QueryCacheProfile::class, 'setResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (! $profile->getResultCacheDriver()) {
|
||||
$defaultResultCacheDriver = $this->_em->getConfiguration()->getResultCache();
|
||||
if ($defaultResultCacheDriver) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$profile = $profile->setResultCacheDriver(DoctrineProvider::wrap($defaultResultCacheDriver));
|
||||
}
|
||||
}
|
||||
@@ -677,6 +681,7 @@ abstract class AbstractQuery
|
||||
$resultCacheDriver = DoctrineProvider::wrap($resultCache);
|
||||
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile
|
||||
// @phpstan-ignore method.deprecated
|
||||
? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
|
||||
: new QueryCacheProfile(0, null, $resultCacheDriver);
|
||||
|
||||
@@ -780,6 +785,7 @@ abstract class AbstractQuery
|
||||
|
||||
// Compatibility for DBAL 2
|
||||
if (! method_exists($this->_queryCacheProfile, 'setResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$this->_queryCacheProfile = $this->_queryCacheProfile->setResultCacheDriver(DoctrineProvider::wrap($cache));
|
||||
|
||||
return $this;
|
||||
@@ -1235,6 +1241,7 @@ abstract class AbstractQuery
|
||||
|
||||
// Support for DBAL 2
|
||||
if (! method_exists($this->_hydrationCacheProfile, 'getResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$cacheDriver = $this->_hydrationCacheProfile->getResultCacheDriver();
|
||||
assert($cacheDriver !== null);
|
||||
|
||||
|
||||
@@ -21,15 +21,13 @@ class AssociationCacheEntry implements CacheEntry
|
||||
* The entity class name
|
||||
*
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
* @var class-string
|
||||
*/
|
||||
public $class;
|
||||
|
||||
/**
|
||||
* @param string $class The entity class.
|
||||
* @param class-string $class The entity class.
|
||||
* @param array<string, mixed> $identifier The entity identifier.
|
||||
* @psalm-param class-string $class
|
||||
*/
|
||||
public function __construct($class, array $identifier)
|
||||
{
|
||||
|
||||
@@ -26,8 +26,7 @@ class CollectionCacheKey extends CacheKey
|
||||
* The owner entity class
|
||||
*
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
* @var class-string
|
||||
*/
|
||||
public $entityClass;
|
||||
|
||||
@@ -40,10 +39,9 @@ class CollectionCacheKey extends CacheKey
|
||||
public $association;
|
||||
|
||||
/**
|
||||
* @param string $entityClass The entity class.
|
||||
* @param class-string $entityClass The entity class.
|
||||
* @param string $association The field name that represents the association.
|
||||
* @param array<string, mixed> $ownerIdentifier The identifier of the owning entity.
|
||||
* @psalm-param class-string $entityClass
|
||||
*/
|
||||
public function __construct($entityClass, $association, array $ownerIdentifier)
|
||||
{
|
||||
|
||||
@@ -25,15 +25,13 @@ class EntityCacheEntry implements CacheEntry
|
||||
* The entity class name
|
||||
*
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
* @var class-string
|
||||
*/
|
||||
public $class;
|
||||
|
||||
/**
|
||||
* @param string $class The entity class.
|
||||
* @param class-string $class The entity class.
|
||||
* @param array<string,mixed> $data The entity data.
|
||||
* @psalm-param class-string $class
|
||||
*/
|
||||
public function __construct($class, array $data)
|
||||
{
|
||||
|
||||
@@ -26,15 +26,13 @@ class EntityCacheKey extends CacheKey
|
||||
* The entity class name
|
||||
*
|
||||
* @readonly Public only for performance reasons, it should be considered immutable.
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
* @var class-string
|
||||
*/
|
||||
public $entityClass;
|
||||
|
||||
/**
|
||||
* @param string $entityClass The entity class name. In a inheritance hierarchy it should always be the root entity class.
|
||||
* @param class-string $entityClass The entity class name. In a inheritance hierarchy it should always be the root entity class.
|
||||
* @param array<string, mixed> $identifier The entity identifier
|
||||
* @psalm-param class-string $entityClass
|
||||
*/
|
||||
public function __construct($entityClass, array $identifier)
|
||||
{
|
||||
|
||||
@@ -254,9 +254,8 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
|
||||
/**
|
||||
* @deprecated This method is not used anymore.
|
||||
*
|
||||
* @param string $targetEntity
|
||||
* @param object $element
|
||||
* @psalm-param class-string $targetEntity
|
||||
* @param class-string $targetEntity
|
||||
* @param object $element
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,7 @@ use Doctrine\ORM\Cache\Region;
|
||||
use Doctrine\ORM\Cache\TimestampCacheKey;
|
||||
use Doctrine\ORM\Cache\TimestampRegion;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Internal\CriteriaOrderings;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
@@ -30,6 +31,8 @@ use function sha1;
|
||||
|
||||
abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
{
|
||||
use CriteriaOrderings;
|
||||
|
||||
/** @var UnitOfWork */
|
||||
protected $uow;
|
||||
|
||||
@@ -475,7 +478,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
|
||||
*/
|
||||
public function loadCriteria(Criteria $criteria)
|
||||
{
|
||||
$orderBy = $criteria->getOrderings();
|
||||
$orderBy = self::getCriteriaOrderings($criteria);
|
||||
$limit = $criteria->getMaxResults();
|
||||
$offset = $criteria->getFirstResult();
|
||||
$query = $this->persister->getSelectSQL($criteria);
|
||||
|
||||
@@ -8,6 +8,8 @@ use Doctrine\ORM\Cache\Exception\CacheException;
|
||||
|
||||
/**
|
||||
* Defines a contract for accessing a particular named region.
|
||||
*
|
||||
* @phpstan-ignore interface.extendsDeprecatedInterface
|
||||
*/
|
||||
interface Region extends MultiGetRegion
|
||||
{
|
||||
|
||||
@@ -72,6 +72,7 @@ class DefaultRegion implements Region
|
||||
CacheItemPoolInterface::class
|
||||
);
|
||||
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->cache = $cacheItemPool;
|
||||
$this->cacheItemPool = CacheAdapter::wrap($cacheItemPool);
|
||||
} elseif (! $cacheItemPool instanceof CacheItemPoolInterface) {
|
||||
@@ -82,6 +83,7 @@ class DefaultRegion implements Region
|
||||
get_debug_type($cacheItemPool)
|
||||
));
|
||||
} else {
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->cache = DoctrineProvider::wrap($cacheItemPool);
|
||||
$this->cacheItemPool = $cacheItemPool;
|
||||
}
|
||||
|
||||
+17
-26
@@ -269,6 +269,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
);
|
||||
|
||||
if (! isset($this->_attributes['entityNamespaces'][$entityNamespaceAlias])) {
|
||||
// @phpstan-ignore staticMethod.deprecatedClass
|
||||
throw UnknownEntityNamespace::fromNamespaceAlias($entityNamespaceAlias);
|
||||
}
|
||||
|
||||
@@ -314,6 +315,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
// Compatibility with DBAL 2
|
||||
if (! method_exists(parent::class, 'getResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$cacheImpl = $this->getResultCacheImpl();
|
||||
|
||||
return $cacheImpl ? CacheAdapter::wrap($cacheImpl) : null;
|
||||
@@ -329,6 +331,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
{
|
||||
// Compatibility with DBAL 2
|
||||
if (! method_exists(parent::class, 'setResultCache')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$this->setResultCacheImpl(DoctrineProvider::wrap($cache));
|
||||
|
||||
return;
|
||||
@@ -684,8 +687,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|callable|null
|
||||
* @psalm-return class-string|callable|null
|
||||
* @return class-string|callable|null
|
||||
*/
|
||||
public function getCustomNumericFunction($name)
|
||||
{
|
||||
@@ -702,7 +704,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* Any previously added numeric functions are discarded.
|
||||
*
|
||||
* @psalm-param array<string, class-string> $functions The map of custom
|
||||
* @param array<string, class-string> $functions The map of custom
|
||||
* DQL numeric functions.
|
||||
*
|
||||
* @return void
|
||||
@@ -737,8 +739,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|callable|null
|
||||
* @psalm-return class-string|callable|null
|
||||
* @return class-string|callable|null
|
||||
*/
|
||||
public function getCustomDatetimeFunction($name)
|
||||
{
|
||||
@@ -804,8 +805,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $modeName The hydration mode name.
|
||||
*
|
||||
* @return string|null The hydrator class name.
|
||||
* @psalm-return class-string<AbstractHydrator>|null
|
||||
* @return class-string<AbstractHydrator>|null The hydrator class name.
|
||||
*/
|
||||
public function getCustomHydrationMode($modeName)
|
||||
{
|
||||
@@ -815,9 +815,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Adds a custom hydration mode.
|
||||
*
|
||||
* @param string $modeName The hydration mode name.
|
||||
* @param string $hydrator The hydrator class name.
|
||||
* @psalm-param class-string<AbstractHydrator> $hydrator
|
||||
* @param string $modeName The hydration mode name.
|
||||
* @param class-string<AbstractHydrator> $hydrator The hydrator class name.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -829,8 +828,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets a class metadata factory.
|
||||
*
|
||||
* @param string $cmfName
|
||||
* @psalm-param class-string $cmfName
|
||||
* @param class-string $cmfName
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -839,10 +837,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
$this->_attributes['classMetadataFactoryName'] = $cmfName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @psalm-return class-string
|
||||
*/
|
||||
/** @return class-string */
|
||||
public function getClassMetadataFactoryName()
|
||||
{
|
||||
if (! isset($this->_attributes['classMetadataFactoryName'])) {
|
||||
@@ -855,9 +850,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Adds a filter to the list of possible filters.
|
||||
*
|
||||
* @param string $name The name of the filter.
|
||||
* @param string $className The class name of the filter.
|
||||
* @psalm-param class-string<SQLFilter> $className
|
||||
* @param string $name The name of the filter.
|
||||
* @param class-string<SQLFilter> $className The class name of the filter.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -871,9 +865,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
*
|
||||
* @param string $name The name of the filter.
|
||||
*
|
||||
* @return string|null The class name of the filter, or null if it is not
|
||||
* defined.
|
||||
* @psalm-return class-string<SQLFilter>|null
|
||||
* @return class-string<SQLFilter>|null The class name of the filter,
|
||||
* or null if it is not defined.
|
||||
*/
|
||||
public function getFilterClassName($name)
|
||||
{
|
||||
@@ -883,8 +876,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Sets default repository class.
|
||||
*
|
||||
* @param string $className
|
||||
* @psalm-param class-string<EntityRepository> $className
|
||||
* @param class-string<EntityRepository> $className
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
@@ -912,8 +904,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
|
||||
/**
|
||||
* Get default repository class.
|
||||
*
|
||||
* @return string
|
||||
* @psalm-return class-string<EntityRepository>
|
||||
* @return class-string<EntityRepository>
|
||||
*/
|
||||
public function getDefaultRepositoryClassName()
|
||||
{
|
||||
|
||||
@@ -50,7 +50,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @param class-string<T> $className
|
||||
*
|
||||
* @psalm-return EntityRepository<T>
|
||||
*
|
||||
@@ -96,6 +96,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
|
||||
E_USER_NOTICE
|
||||
);
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
return $this->wrapped->transactional($func);
|
||||
}
|
||||
|
||||
|
||||
+38
-29
@@ -30,9 +30,7 @@ use Doctrine\ORM\Query\FilterCollection;
|
||||
use Doctrine\ORM\Query\ResultSetMapping;
|
||||
use Doctrine\ORM\Repository\RepositoryFactory;
|
||||
use Doctrine\Persistence\Mapping\MappingException;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
use function array_keys;
|
||||
use function class_exists;
|
||||
@@ -162,8 +160,9 @@ class EntityManager implements EntityManagerInterface
|
||||
throw MissingMappingDriverImplementation::create();
|
||||
}
|
||||
|
||||
$this->conn = $conn;
|
||||
$this->config = $config;
|
||||
$this->conn = $conn;
|
||||
$this->config = $config;
|
||||
// @phpstan-ignore method.deprecated
|
||||
$this->eventManager = $eventManager ?? $conn->getEventManager();
|
||||
|
||||
$metadataFactoryClassName = $config->getClassMetadataFactoryName();
|
||||
@@ -246,18 +245,24 @@ class EntityManager implements EntityManagerInterface
|
||||
|
||||
$this->conn->beginTransaction();
|
||||
|
||||
$successful = false;
|
||||
|
||||
try {
|
||||
$return = $func($this);
|
||||
|
||||
$this->flush();
|
||||
$this->conn->commit();
|
||||
|
||||
return $return ?: true;
|
||||
} catch (Throwable $e) {
|
||||
$this->close();
|
||||
$this->conn->rollBack();
|
||||
$successful = true;
|
||||
|
||||
throw $e;
|
||||
return $return ?: true;
|
||||
} finally {
|
||||
if (! $successful) {
|
||||
$this->close();
|
||||
if ($this->conn->isTransactionActive()) {
|
||||
$this->conn->rollBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,18 +273,24 @@ class EntityManager implements EntityManagerInterface
|
||||
{
|
||||
$this->conn->beginTransaction();
|
||||
|
||||
$successful = false;
|
||||
|
||||
try {
|
||||
$return = $func($this);
|
||||
|
||||
$this->flush();
|
||||
$this->conn->commit();
|
||||
|
||||
return $return;
|
||||
} catch (Throwable $e) {
|
||||
$this->close();
|
||||
$this->conn->rollBack();
|
||||
$successful = true;
|
||||
|
||||
throw $e;
|
||||
return $return;
|
||||
} finally {
|
||||
if (! $successful) {
|
||||
$this->close();
|
||||
if ($this->conn->isTransactionActive()) {
|
||||
$this->conn->rollBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,25 +417,23 @@ class EntityManager implements EntityManagerInterface
|
||||
/**
|
||||
* 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 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.
|
||||
* @psalm-param class-string<T> $className
|
||||
* @param class-string<T> $className The class name of the entity to find.
|
||||
* @param mixed $id The identity of the entity to find.
|
||||
* @param 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.
|
||||
* @psalm-param LockMode::*|null $lockMode
|
||||
*
|
||||
* @return object|null The entity instance or NULL if the entity can not be found.
|
||||
* @psalm-return ?T
|
||||
* @return T|null The entity instance or NULL if the entity can not be found.
|
||||
*
|
||||
* @throws OptimisticLockException
|
||||
* @throws ORMInvalidArgumentException
|
||||
* @throws TransactionRequiredException
|
||||
* @throws ORMException
|
||||
*
|
||||
* @template T
|
||||
* @template T of object
|
||||
*/
|
||||
public function find($className, $id, $lockMode = null, $lockVersion = null)
|
||||
{
|
||||
@@ -615,6 +624,7 @@ class EntityManager implements EntityManagerInterface
|
||||
public function clear($entityName = null)
|
||||
{
|
||||
if ($entityName !== null && ! is_string($entityName)) {
|
||||
// @phpstan-ignore staticMethod.deprecated
|
||||
throw ORMInvalidArgumentException::invalidEntityName($entityName);
|
||||
}
|
||||
|
||||
@@ -801,11 +811,9 @@ class EntityManager implements EntityManagerInterface
|
||||
/**
|
||||
* Gets the repository for an entity class.
|
||||
*
|
||||
* @param string $entityName The name of the entity.
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @param class-string<T> $entityName The name of the entity.
|
||||
*
|
||||
* @return ObjectRepository|EntityRepository The repository class.
|
||||
* @psalm-return EntityRepository<T>
|
||||
* @return EntityRepository<T> The repository class.
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
@@ -1109,6 +1117,7 @@ class EntityManager implements EntityManagerInterface
|
||||
|
||||
private function configureLegacyMetadataCache(): void
|
||||
{
|
||||
// @phpstan-ignore method.deprecated
|
||||
$metadataCache = $this->config->getMetadataCacheImpl();
|
||||
if (! $metadataCache) {
|
||||
return;
|
||||
|
||||
@@ -29,9 +29,9 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @param class-string<T> $className
|
||||
*
|
||||
* @psalm-return EntityRepository<T>
|
||||
* @return EntityRepository<T>
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
@@ -172,12 +172,10 @@ interface EntityManagerInterface extends ObjectManager
|
||||
* Gets a reference to the entity identified by the given type and identifier
|
||||
* without actually loading it, if the entity is not yet loaded.
|
||||
*
|
||||
* @param string $entityName The name of the entity type.
|
||||
* @param mixed $id The entity identifier.
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @param class-string<T> $entityName The name of the entity type.
|
||||
* @param mixed $id The entity identifier.
|
||||
*
|
||||
* @return object|null The entity reference.
|
||||
* @psalm-return T|null
|
||||
* @return T|null The entity reference.
|
||||
*
|
||||
* @throws ORMException
|
||||
*
|
||||
@@ -202,12 +200,10 @@ interface EntityManagerInterface extends ObjectManager
|
||||
*
|
||||
* @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @param string $entityName The name of the entity type.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @param class-string<T> $entityName The name of the entity type.
|
||||
* @param mixed $identifier The entity identifier.
|
||||
*
|
||||
* @return object|null The (partial) entity reference
|
||||
* @psalm-return T|null
|
||||
* @return T|null The (partial) entity reference
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
@@ -337,10 +333,10 @@ interface EntityManagerInterface extends ObjectManager
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param string|class-string<T> $className
|
||||
* @param string|class-string<T> $className
|
||||
*
|
||||
* @return Mapping\ClassMetadata
|
||||
* @psalm-return Mapping\ClassMetadata<T>
|
||||
* @psalm-return ($className is class-string<T> ? Mapping\ClassMetadata<T> : Mapping\ClassMetadata<object>)
|
||||
*
|
||||
* @psalm-template T of object
|
||||
*/
|
||||
|
||||
@@ -42,8 +42,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
/**
|
||||
* @internal This property will be private in 3.0, call {@see getEntityName()} instead.
|
||||
*
|
||||
* @var string
|
||||
* @psalm-var class-string<T>
|
||||
* @var class-string<T>
|
||||
*/
|
||||
protected $_entityName;
|
||||
|
||||
@@ -287,10 +286,7 @@ class EntityRepository implements ObjectRepository, Selectable
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @psalm-return class-string<T>
|
||||
*/
|
||||
/** @return class-string<T> */
|
||||
protected function getEntityName()
|
||||
{
|
||||
return $this->_entityName;
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PostLoadEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PostPersistEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PostRemoveEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PostUpdateEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PrePersistEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
/** @phpstan-ignore class.extendsDeprecatedClass */
|
||||
final class PreRemoveEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ use function sprintf;
|
||||
|
||||
/**
|
||||
* Class that holds event arguments for a preUpdate event.
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
@@ -26,6 +28,7 @@ class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
*/
|
||||
public function __construct($entity, EntityManagerInterface $em, array &$changeSet)
|
||||
{
|
||||
// @phpstan-ignore staticMethod.deprecatedClass
|
||||
parent::__construct($entity, $em);
|
||||
|
||||
$this->entityChangeSet = &$changeSet;
|
||||
|
||||
@@ -8,6 +8,8 @@ use Doctrine\ORM\ORMException as BaseORMException;
|
||||
|
||||
/**
|
||||
* Should become an interface in 3.0
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class ORMException extends BaseORMException
|
||||
{
|
||||
|
||||
@@ -73,6 +73,7 @@ abstract class AbstractIdGenerator
|
||||
throw new InvalidArgumentException('Unsupported entity manager implementation.');
|
||||
}
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
return $this->generate($em, $entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Internal;
|
||||
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\Order;
|
||||
|
||||
use function array_map;
|
||||
use function class_exists;
|
||||
use function method_exists;
|
||||
use function strtoupper;
|
||||
|
||||
trait CriteriaOrderings
|
||||
{
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*
|
||||
* @psalm-suppress DeprecatedMethod We need to call the deprecated API if the new one does not exist yet.
|
||||
*/
|
||||
private static function getCriteriaOrderings(Criteria $criteria): array
|
||||
{
|
||||
if (! method_exists(Criteria::class, 'orderings')) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
return $criteria->getOrderings();
|
||||
}
|
||||
|
||||
return array_map(
|
||||
static function (Order $order): string {
|
||||
return $order->value;
|
||||
},
|
||||
$criteria->orderings()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $orderings
|
||||
*
|
||||
* @return array<string, string>|array<string, Order>
|
||||
*/
|
||||
private static function mapToOrderEnumIfAvailable(array $orderings): array
|
||||
{
|
||||
if (! class_exists(Order::class)) {
|
||||
return $orderings;
|
||||
}
|
||||
|
||||
return array_map(
|
||||
static function (string $order): Order {
|
||||
return Order::from(strtoupper($order));
|
||||
},
|
||||
$orderings
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -182,29 +182,31 @@ abstract class AbstractHydrator
|
||||
|
||||
$this->prepare();
|
||||
|
||||
while (true) {
|
||||
$row = $this->statement()->fetchAssociative();
|
||||
try {
|
||||
while (true) {
|
||||
$row = $this->statement()->fetchAssociative();
|
||||
|
||||
if ($row === false) {
|
||||
$this->cleanup();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
$this->hydrateRowData($row, $result);
|
||||
|
||||
$this->cleanupAfterRowIteration();
|
||||
if (count($result) === 1) {
|
||||
if (count($resultSetMapping->indexByMap) === 0) {
|
||||
yield end($result);
|
||||
} else {
|
||||
yield from $result;
|
||||
if ($row === false) {
|
||||
break;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
$this->hydrateRowData($row, $result);
|
||||
|
||||
$this->cleanupAfterRowIteration();
|
||||
if (count($result) === 1) {
|
||||
if (count($resultSetMapping->indexByMap) === 0) {
|
||||
yield end($result);
|
||||
} else {
|
||||
yield from $result;
|
||||
}
|
||||
} else {
|
||||
yield $result;
|
||||
}
|
||||
} else {
|
||||
yield $result;
|
||||
}
|
||||
} finally {
|
||||
$this->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ class ObjectHydrator extends AbstractHydrator
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
* @psalm-param array<string, mixed> $data
|
||||
*
|
||||
* @return mixed
|
||||
@@ -367,11 +367,15 @@ class ObjectHydrator extends AbstractHydrator
|
||||
$parentObject = $this->resultPointers[$parentAlias];
|
||||
} else {
|
||||
// Parent object of relation not found, mark as not-fetched again
|
||||
$element = $this->getEntity($data, $dqlAlias);
|
||||
if (isset($nonemptyComponents[$dqlAlias])) {
|
||||
$element = $this->getEntity($data, $dqlAlias);
|
||||
|
||||
// Update result pointer and provide initial fetch data for parent
|
||||
$this->resultPointers[$dqlAlias] = $element;
|
||||
$rowData['data'][$parentAlias][$relationField] = $element;
|
||||
// Update result pointer and provide initial fetch data for parent
|
||||
$this->resultPointers[$dqlAlias] = $element;
|
||||
$rowData['data'][$parentAlias][$relationField] = $element;
|
||||
} else {
|
||||
$element = null;
|
||||
}
|
||||
|
||||
// Mark as not-fetched again
|
||||
unset($this->_hints['fetched'][$parentAlias][$relationField]);
|
||||
|
||||
@@ -76,11 +76,11 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* Do an optimized search of an element
|
||||
*
|
||||
* @template TMaybeContained
|
||||
* @param mixed $element The element to search for.
|
||||
*
|
||||
* @return bool TRUE if the collection contains $element, FALSE otherwise.
|
||||
*/
|
||||
public function contains($element)
|
||||
{
|
||||
|
||||
@@ -172,6 +172,8 @@ class ClassMetadataBuilder
|
||||
/**
|
||||
* Adds named query.
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $dqlQuery
|
||||
*
|
||||
@@ -216,11 +218,11 @@ class ClassMetadataBuilder
|
||||
/**
|
||||
* Sets the discriminator column details.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @param int $length
|
||||
* @psalm-param class-string<BackedEnum>|null $enumType
|
||||
* @psalm-param array<string, mixed> $options
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
* @param int $length
|
||||
* @param class-string<BackedEnum>|null $enumType
|
||||
* @param array<string, mixed> $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
@@ -420,7 +420,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
/**
|
||||
* Gets the lower-case short name of a class.
|
||||
*
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
*/
|
||||
private function getShortName(string $className): string
|
||||
{
|
||||
@@ -558,6 +558,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
{
|
||||
foreach ($parentClass->namedQueries as $name => $query) {
|
||||
if (! isset($subClass->namedQueries[$name])) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$subClass->addNamedQuery(
|
||||
[
|
||||
'name' => $query['name'],
|
||||
@@ -575,6 +576,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
{
|
||||
foreach ($parentClass->namedNativeQueries as $name => $query) {
|
||||
if (! isset($subClass->namedNativeQueries[$name])) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$subClass->addNamedNativeQuery(
|
||||
[
|
||||
'name' => $query['name'],
|
||||
@@ -637,7 +639,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
$platform = $this->getTargetPlatform();
|
||||
|
||||
// Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
|
||||
/** @psalm-suppress UndefinedClass, InvalidClass */
|
||||
/** @psalm-suppress UndefinedClass, InvalidClass */ // @phpstan-ignore method.deprecated
|
||||
if (! $platform instanceof MySQLPlatform && ! $platform instanceof SqlitePlatform && ! $platform instanceof SQLServerPlatform && $platform->usesSequenceEmulatedIdentityColumns()) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -654,8 +656,9 @@ DEPRECATION
|
||||
$columnName = $class->getSingleIdentifierColumnName();
|
||||
$quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
|
||||
$sequencePrefix = $class->getSequencePrefix($this->getTargetPlatform());
|
||||
$sequenceName = $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix, $columnName);
|
||||
$definition = [
|
||||
// @phpstan-ignore method.deprecated
|
||||
$sequenceName = $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix, $columnName);
|
||||
$definition = [
|
||||
'sequenceName' => $this->truncateSequenceName($sequenceName),
|
||||
];
|
||||
|
||||
@@ -711,6 +714,7 @@ DEPRECATION
|
||||
$class->setIdGenerator(new AssignedGenerator());
|
||||
break;
|
||||
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
case ClassMetadata::GENERATOR_TYPE_UUID:
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -718,6 +722,7 @@ DEPRECATION
|
||||
'Mapping for %s: the "UUID" id generator strategy is deprecated with no replacement',
|
||||
$class->name
|
||||
);
|
||||
// @phpstan-ignore new.deprecated
|
||||
$class->setIdGenerator(new UuidGenerator());
|
||||
break;
|
||||
|
||||
@@ -845,8 +850,10 @@ DEPRECATION
|
||||
*/
|
||||
protected function getFqcnFromAlias($namespaceAlias, $simpleClassName)
|
||||
{
|
||||
/** @psalm-var class-string */
|
||||
return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
|
||||
/** @var class-string $classString */
|
||||
$classString = $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
|
||||
|
||||
return $classString;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -257,8 +257,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* READ-ONLY: The name of the entity class.
|
||||
*
|
||||
* @var string
|
||||
* @psalm-var class-string<T>
|
||||
* @var class-string<T>
|
||||
*/
|
||||
public $name;
|
||||
|
||||
@@ -275,8 +274,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* hierarchy. If the entity is not part of a mapped inheritance hierarchy this is the same
|
||||
* as {@link $name}.
|
||||
*
|
||||
* @var string
|
||||
* @psalm-var class-string
|
||||
* @var class-string
|
||||
*/
|
||||
public $rootEntityName;
|
||||
|
||||
@@ -300,8 +298,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* The name of the custom repository class used for the entity class.
|
||||
* (Optional).
|
||||
*
|
||||
* @var string|null
|
||||
* @psalm-var ?class-string<EntityRepository>
|
||||
* @var class-string<EntityRepository>|null
|
||||
*/
|
||||
public $customRepositoryClassName;
|
||||
|
||||
@@ -323,7 +320,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* READ-ONLY: The names of the parent <em>entity</em> classes (ancestors), starting with the
|
||||
* nearest one and ending with the root entity class.
|
||||
*
|
||||
* @psalm-var list<class-string>
|
||||
* @var list<class-string>
|
||||
*/
|
||||
public $parentClasses = [];
|
||||
|
||||
@@ -350,7 +347,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* For subclasses of such root entities, the list can be reused/passed downwards, it only needs to
|
||||
* be filtered accordingly (only keep remaining subclasses)
|
||||
*
|
||||
* @psalm-var list<class-string>
|
||||
* @var list<class-string>
|
||||
*/
|
||||
public $subClasses = [];
|
||||
|
||||
@@ -548,9 +545,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*
|
||||
* @see discriminatorColumn
|
||||
*
|
||||
* @var array<int|string, string>
|
||||
*
|
||||
* @psalm-var array<int|string, class-string>
|
||||
* @var array<int|string, class-string>
|
||||
*/
|
||||
public $discriminatorMap = [];
|
||||
|
||||
@@ -811,8 +806,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
|
||||
* metadata of the class with the given name.
|
||||
*
|
||||
* @param string $entityName The name of the entity class the new instance is used for.
|
||||
* @psalm-param class-string<T> $entityName
|
||||
* @param class-string<T> $entityName The name of the entity class the new instance is used for.
|
||||
*/
|
||||
public function __construct($entityName, ?NamingStrategy $namingStrategy = null, ?TypedFieldMapper $typedFieldMapper = null)
|
||||
{
|
||||
@@ -1405,6 +1399,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function getColumnName($fieldName)
|
||||
{
|
||||
// @phpstan-ignore property.deprecated
|
||||
return $this->columnNames[$fieldName] ?? $fieldName;
|
||||
}
|
||||
|
||||
@@ -1659,6 +1654,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
$mapping['quoted'] = true;
|
||||
}
|
||||
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->columnNames[$mapping['fieldName']] = $mapping['columnName'];
|
||||
|
||||
if (isset($this->fieldNames[$mapping['columnName']]) || ($this->discriminatorColumn && $this->discriminatorColumn['name'] === $mapping['columnName'])) {
|
||||
@@ -1683,6 +1679,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) {
|
||||
if (isset($mapping['id']) && $mapping['id'] === true) {
|
||||
throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName'], $mapping['type']);
|
||||
@@ -2423,7 +2420,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* Assumes that the class names in the passed array are in the order:
|
||||
* directParent -> directParentParent -> directParentParentParent ... -> root.
|
||||
*
|
||||
* @psalm-param list<class-string> $classNames
|
||||
* @param list<class-string> $classNames
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -2576,6 +2573,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
|
||||
unset($this->fieldMappings[$fieldName]);
|
||||
unset($this->fieldNames[$mapping['columnName']]);
|
||||
// @phpstan-ignore property.deprecated
|
||||
unset($this->columnNames[$mapping['fieldName']]);
|
||||
|
||||
$overrideMapping = $this->validateAndCompleteFieldMapping($overrideMapping);
|
||||
@@ -2699,6 +2697,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
private function isInheritanceType(int $type): bool
|
||||
{
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
if ($type === self::INHERITANCE_TYPE_TABLE_PER_CLASS) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -2710,6 +2709,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
return $type === self::INHERITANCE_TYPE_NONE ||
|
||||
$type === self::INHERITANCE_TYPE_SINGLE_TABLE ||
|
||||
$type === self::INHERITANCE_TYPE_JOINED ||
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
$type === self::INHERITANCE_TYPE_TABLE_PER_CLASS;
|
||||
}
|
||||
|
||||
@@ -2766,8 +2766,9 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
public function addInheritedFieldMapping(array $fieldMapping)
|
||||
{
|
||||
$this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
|
||||
$this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
|
||||
$this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
|
||||
// @phpstan-ignore property.deprecated
|
||||
$this->columnNames[$fieldMapping['fieldName']] = $fieldMapping['columnName'];
|
||||
$this->fieldNames[$fieldMapping['columnName']] = $fieldMapping['fieldName'];
|
||||
|
||||
if (isset($fieldMapping['generated'])) {
|
||||
$this->requiresFetchAfterChange = true;
|
||||
@@ -3017,8 +3018,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
/**
|
||||
* Registers a custom repository class for the entity class.
|
||||
*
|
||||
* @param string|null $repositoryClassName The class name of the custom mapper.
|
||||
* @psalm-param class-string<EntityRepository>|null $repositoryClassName
|
||||
* @param class-string<EntityRepository>|null $repositoryClassName The class name of the custom mapper.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -3555,8 +3555,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*
|
||||
* @param string $assocName
|
||||
*
|
||||
* @return string
|
||||
* @psalm-return class-string
|
||||
* @return class-string
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
@@ -3681,6 +3680,17 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function getAssociationMappedByTargetField($fieldName)
|
||||
{
|
||||
if (! $this->isAssociationInverseSide($fieldName)) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11309',
|
||||
'Calling %s with owning side field %s is deprecated and will no longer be supported in Doctrine ORM 3.0. Call %s::isAssociationInverseSide() to check first.',
|
||||
__METHOD__,
|
||||
$fieldName,
|
||||
self::class
|
||||
);
|
||||
}
|
||||
|
||||
return $this->associationMappings[$fieldName]['mappedBy'];
|
||||
}
|
||||
|
||||
@@ -3707,7 +3717,6 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
* @param string|null $className
|
||||
*
|
||||
* @return string|null null if the input value is null
|
||||
* @psalm-return class-string|null
|
||||
*/
|
||||
public function fullyQualifiedClassName($className)
|
||||
{
|
||||
@@ -3849,6 +3858,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
if ($schemaName) {
|
||||
$sequencePrefix = $schemaName . '.' . $tableName;
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (! $platform->supportsSchemas() && $platform->canEmulateSchemas()) {
|
||||
$sequencePrefix = $schemaName . '__' . $tableName;
|
||||
}
|
||||
@@ -3865,7 +3875,7 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
/** @psalm-param class-string $class */
|
||||
/** @param class-string $class */
|
||||
private function getAccessibleProperty(ReflectionService $reflService, string $class, string $field): ?ReflectionProperty
|
||||
{
|
||||
$reflectionProperty = $reflService->getAccessibleProperty($class, $field);
|
||||
@@ -3880,6 +3890,10 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
}
|
||||
}
|
||||
|
||||
if (PHP_VERSION_ID >= 80400 && $reflectionProperty !== null && count($reflectionProperty->getHooks()) > 0) {
|
||||
throw new LogicException('Doctrine ORM does not support property hooks in this version. Check https://github.com/doctrine/orm/issues/11624 for details of versions that support property hooks.');
|
||||
}
|
||||
|
||||
return $reflectionProperty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use function trim;
|
||||
*/
|
||||
class DefaultEntityListenerResolver implements EntityListenerResolver
|
||||
{
|
||||
/** @psalm-var array<class-string, object> Map to store entity listener instances. */
|
||||
/** @var array<class-string, object> Map to store entity listener instances. */
|
||||
private $instances = [];
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,7 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
if (! empty($class->table['schema'])) {
|
||||
$tableName = $class->table['schema'] . '.' . $class->table['name'];
|
||||
|
||||
// @phpstan-ignore method.deprecated
|
||||
if (! $platform->supportsSchemas() && $platform->canEmulateSchemas()) {
|
||||
$tableName = $class->table['schema'] . '__' . $class->table['name'];
|
||||
}
|
||||
@@ -90,7 +91,8 @@ class DefaultQuoteStrategy implements QuoteStrategy
|
||||
$schema = '';
|
||||
|
||||
if (isset($association['joinTable']['schema'])) {
|
||||
$schema = $association['joinTable']['schema'];
|
||||
$schema = $association['joinTable']['schema'];
|
||||
// @phpstan-ignore method.deprecated
|
||||
$schema .= ! $platform->supportsSchemas() && $platform->canEmulateSchemas() ? '__' : '.';
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use BackedEnum;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
@@ -16,6 +17,7 @@ use ReflectionProperty;
|
||||
use function array_merge;
|
||||
use function assert;
|
||||
use function enum_exists;
|
||||
use function is_a;
|
||||
|
||||
use const PHP_VERSION_ID;
|
||||
|
||||
@@ -54,18 +56,18 @@ final class DefaultTypedFieldMapper implements TypedFieldMapper
|
||||
&& ($type instanceof ReflectionNamedType)
|
||||
) {
|
||||
if (PHP_VERSION_ID >= 80100 && ! $type->isBuiltin() && enum_exists($type->getName())) {
|
||||
$mapping['enumType'] = $type->getName();
|
||||
|
||||
$reflection = new ReflectionEnum($type->getName());
|
||||
if (! $reflection->isBacked()) {
|
||||
throw MappingException::backedEnumTypeRequired(
|
||||
$field->class,
|
||||
$mapping['fieldName'],
|
||||
$mapping['enumType']
|
||||
$type->getName()
|
||||
);
|
||||
}
|
||||
|
||||
$type = $reflection->getBackingType();
|
||||
assert(is_a($type->getName(), BackedEnum::class, true));
|
||||
$mapping['enumType'] = $type->getName();
|
||||
$type = $reflection->getBackingType();
|
||||
|
||||
assert($type instanceof ReflectionNamedType);
|
||||
}
|
||||
|
||||
@@ -47,10 +47,7 @@ class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
*/
|
||||
protected $reader;
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @psalm-var array<class-string, int>
|
||||
*/
|
||||
/** @var array<class-string, int> */
|
||||
protected $entityAnnotationClasses = [
|
||||
Mapping\Entity::class => 1,
|
||||
Mapping\MappedSuperclass::class => 2,
|
||||
@@ -89,8 +86,8 @@ class AnnotationDriver extends CompatibilityAnnotationDriver
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
|
||||
@@ -65,6 +65,7 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
$this->reader = new AttributeReader();
|
||||
$this->addPaths($paths);
|
||||
|
||||
// @phpstan-ignore property.deprecated
|
||||
if ($this->entityAnnotationClasses !== self::ENTITY_ATTRIBUTE_CLASSES) {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
@@ -114,6 +115,7 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
|
||||
foreach ($classAttributes as $a) {
|
||||
$attr = $a instanceof RepeatableAttributeCollection ? $a[0] : $a;
|
||||
// @phpstan-ignore property.deprecated
|
||||
if (isset($this->entityAnnotationClasses[get_class($attr)])) {
|
||||
return false;
|
||||
}
|
||||
@@ -125,8 +127,8 @@ class AttributeDriver extends CompatibilityAnnotationDriver
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
|
||||
@@ -185,8 +185,8 @@ class DatabaseDriver implements MappingDriver
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
@@ -533,7 +533,7 @@ class DatabaseDriver implements MappingDriver
|
||||
/**
|
||||
* Returns the mapped class name for a table if it exists. Otherwise return "classified" version.
|
||||
*
|
||||
* @psalm-return class-string
|
||||
* @return class-string
|
||||
*/
|
||||
private function getClassNameForTable(string $tableName): string
|
||||
{
|
||||
|
||||
@@ -10,6 +10,8 @@ use Doctrine\Persistence\Mapping\Driver\SymfonyFileLocator;
|
||||
* YamlDriver that additionally looks for mapping information in a global file.
|
||||
*
|
||||
* @deprecated This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @phpstan-ignore class.extendsDeprecatedClass
|
||||
*/
|
||||
class SimplifiedYamlDriver extends YamlDriver
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\Order;
|
||||
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
@@ -16,6 +17,7 @@ use LogicException;
|
||||
use SimpleXMLElement;
|
||||
|
||||
use function assert;
|
||||
use function class_exists;
|
||||
use function constant;
|
||||
use function count;
|
||||
use function defined;
|
||||
@@ -35,6 +37,8 @@ use function strtoupper;
|
||||
* XmlDriver is a metadata driver that enables mapping through XML files.
|
||||
*
|
||||
* @link www.doctrine-project.org
|
||||
*
|
||||
* @template-extends FileDriver<SimpleXMLElement>
|
||||
*/
|
||||
class XmlDriver extends FileDriver
|
||||
{
|
||||
@@ -69,15 +73,14 @@ class XmlDriver extends FileDriver
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
public function loadMetadataForClass($className, PersistenceClassMetadata $metadata)
|
||||
{
|
||||
$xmlRoot = $this->getElement($className);
|
||||
assert($xmlRoot instanceof SimpleXMLElement);
|
||||
|
||||
if ($xmlRoot->getName() === 'entity') {
|
||||
if (isset($xmlRoot['repository-class'])) {
|
||||
@@ -119,6 +122,7 @@ class XmlDriver extends FileDriver
|
||||
// Evaluate named queries
|
||||
if (isset($xmlRoot->{'named-queries'})) {
|
||||
foreach ($xmlRoot->{'named-queries'}->{'named-query'} ?? [] as $namedQueryElement) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$metadata->addNamedQuery(
|
||||
[
|
||||
'name' => (string) $namedQueryElement['name'],
|
||||
@@ -131,6 +135,7 @@ class XmlDriver extends FileDriver
|
||||
// Evaluate native named queries
|
||||
if (isset($xmlRoot->{'named-native-queries'})) {
|
||||
foreach ($xmlRoot->{'named-native-queries'}->{'named-native-query'} ?? [] as $nativeQueryElement) {
|
||||
// @phpstan-ignore method.deprecated
|
||||
$metadata->addNamedNativeQuery(
|
||||
[
|
||||
'name' => isset($nativeQueryElement['name']) ? (string) $nativeQueryElement['name'] : null,
|
||||
@@ -201,6 +206,7 @@ class XmlDriver extends FileDriver
|
||||
];
|
||||
|
||||
if (isset($discrColumn['options'])) {
|
||||
assert($discrColumn['options'] instanceof SimpleXMLElement);
|
||||
$columnDef['options'] = $this->parseOptions($discrColumn['options']->children());
|
||||
}
|
||||
|
||||
@@ -212,6 +218,7 @@ class XmlDriver extends FileDriver
|
||||
// Evaluate <discriminator-map...>
|
||||
if (isset($xmlRoot->{'discriminator-map'})) {
|
||||
$map = [];
|
||||
assert($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} instanceof SimpleXMLElement);
|
||||
foreach ($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} as $discrMapElement) {
|
||||
$map[(string) $discrMapElement['value']] = (string) $discrMapElement['class'];
|
||||
}
|
||||
@@ -481,9 +488,11 @@ class XmlDriver extends FileDriver
|
||||
if (isset($oneToManyElement->{'order-by'})) {
|
||||
$orderBy = [];
|
||||
foreach ($oneToManyElement->{'order-by'}->{'order-by-field'} ?? [] as $orderByField) {
|
||||
/** @psalm-suppress DeprecatedConstant */
|
||||
$orderBy[(string) $orderByField['name']] = isset($orderByField['direction'])
|
||||
? (string) $orderByField['direction']
|
||||
: Criteria::ASC;
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
: (class_exists(Order::class) ? (Order::Ascending)->value : Criteria::ASC);
|
||||
}
|
||||
|
||||
$mapping['orderBy'] = $orderBy;
|
||||
@@ -609,9 +618,11 @@ class XmlDriver extends FileDriver
|
||||
if (isset($manyToManyElement->{'order-by'})) {
|
||||
$orderBy = [];
|
||||
foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} ?? [] as $orderByField) {
|
||||
/** @psalm-suppress DeprecatedConstant */
|
||||
$orderBy[(string) $orderByField['name']] = isset($orderByField['direction'])
|
||||
? (string) $orderByField['direction']
|
||||
: Criteria::ASC;
|
||||
// @phpstan-ignore classConstant.deprecated
|
||||
: (class_exists(Order::class) ? (Order::Ascending)->value : Criteria::ASC);
|
||||
}
|
||||
|
||||
$mapping['orderBy'] = $orderBy;
|
||||
@@ -960,19 +971,19 @@ class XmlDriver extends FileDriver
|
||||
|
||||
if (isset($xmlElement->entity)) {
|
||||
foreach ($xmlElement->entity as $entityElement) {
|
||||
/** @psalm-var class-string $entityName */
|
||||
/** @var class-string $entityName */
|
||||
$entityName = (string) $entityElement['name'];
|
||||
$result[$entityName] = $entityElement;
|
||||
}
|
||||
} elseif (isset($xmlElement->{'mapped-superclass'})) {
|
||||
foreach ($xmlElement->{'mapped-superclass'} as $mappedSuperClass) {
|
||||
/** @psalm-var class-string $className */
|
||||
/** @var class-string $className */
|
||||
$className = (string) $mappedSuperClass['name'];
|
||||
$result[$className] = $mappedSuperClass;
|
||||
}
|
||||
} elseif (isset($xmlElement->embeddable)) {
|
||||
foreach ($xmlElement->embeddable as $embeddableElement) {
|
||||
/** @psalm-var class-string $embeddableName */
|
||||
/** @var class-string $embeddableName */
|
||||
$embeddableName = (string) $embeddableElement['name'];
|
||||
$result[$embeddableName] = $embeddableElement;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ use function substr;
|
||||
* The YamlDriver reads the mapping metadata from yaml schema files.
|
||||
*
|
||||
* @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
|
||||
*
|
||||
* @template-extends FileDriver<array<string, mixed>>
|
||||
*/
|
||||
class YamlDriver extends FileDriver
|
||||
{
|
||||
@@ -61,8 +63,8 @@ class YamlDriver extends FileDriver
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-param class-string<T> $className
|
||||
* @psalm-param ClassMetadata<T> $metadata
|
||||
* @param class-string<T> $className
|
||||
* @param ClassMetadata<T> $metadata
|
||||
*
|
||||
* @template T of object
|
||||
*/
|
||||
|
||||
@@ -18,8 +18,7 @@ use Doctrine\ORM\EntityRepository;
|
||||
final class Entity implements MappingAttribute
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
* @psalm-var class-string<EntityRepository<T>>|null
|
||||
* @var class-string<EntityRepository<T>>|null
|
||||
* @readonly
|
||||
*/
|
||||
public $repositoryClass;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
use Attribute;
|
||||
|
||||
@@ -17,13 +17,12 @@ use Doctrine\ORM\EntityRepository;
|
||||
final class MappedSuperclass implements MappingAttribute
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
* @psalm-var class-string<EntityRepository>|null
|
||||
* @var class-string<EntityRepository>|null
|
||||
* @readonly
|
||||
*/
|
||||
public $repositoryClass;
|
||||
|
||||
/** @psalm-param class-string<EntityRepository>|null $repositoryClass */
|
||||
/** @param class-string<EntityRepository>|null $repositoryClass */
|
||||
public function __construct(?string $repositoryClass = null)
|
||||
{
|
||||
$this->repositoryClass = $repositoryClass;
|
||||
|
||||
@@ -4,7 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Mapping;
|
||||
|
||||
/** A marker interface for mapping attributes. */
|
||||
/**
|
||||
* A marker interface for mapping attributes.
|
||||
*
|
||||
* @phpstan-ignore interface.extendsDeprecatedInterface
|
||||
*/
|
||||
interface MappingAttribute extends Annotation
|
||||
{
|
||||
}
|
||||
|
||||
@@ -33,8 +33,7 @@ final class ReflectionPropertiesGetter
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
*
|
||||
* @return ReflectionProperty[] indexed by property internal name
|
||||
*/
|
||||
@@ -57,7 +56,7 @@ final class ReflectionPropertiesGetter
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param class-string $className
|
||||
* @param class-string $className
|
||||
*
|
||||
* @return ReflectionClass[]
|
||||
* @psalm-return list<ReflectionClass<object>>
|
||||
|
||||
+9
-1
@@ -50,7 +50,15 @@ class NativeQuery extends AbstractQuery
|
||||
$types = [];
|
||||
|
||||
foreach ($this->getParameters() as $parameter) {
|
||||
$name = $parameter->getName();
|
||||
$name = $parameter->getName();
|
||||
|
||||
if ($parameter->typeWasSpecified()) {
|
||||
$parameters[$name] = $parameter->getValue();
|
||||
$types[$name] = $parameter->getType();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $this->processParameterValue($parameter->getValue());
|
||||
$type = $parameter->getValue() === $value
|
||||
? $parameter->getType()
|
||||
|
||||
+49
-45
@@ -5,11 +5,31 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\Common\Cache\Cache as CacheDriver;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Doctrine\ORM\Cache\Exception\InvalidResultCacheDriver;
|
||||
use Doctrine\ORM\Cache\Exception\MetadataCacheNotConfigured;
|
||||
use Doctrine\ORM\Cache\Exception\MetadataCacheUsesNonPersistentCache;
|
||||
use Doctrine\ORM\Cache\Exception\QueryCacheNotConfigured;
|
||||
use Doctrine\ORM\Cache\Exception\QueryCacheUsesNonPersistentCache;
|
||||
use Doctrine\ORM\Exception\EntityManagerClosed;
|
||||
use Doctrine\ORM\Exception\InvalidEntityRepository;
|
||||
use Doctrine\ORM\Exception\InvalidHydrationMode;
|
||||
use Doctrine\ORM\Exception\MismatchedEventManager;
|
||||
use Doctrine\ORM\Exception\MissingIdentifierField;
|
||||
use Doctrine\ORM\Exception\MissingMappingDriverImplementation;
|
||||
use Doctrine\ORM\Exception\NamedNativeQueryNotFound;
|
||||
use Doctrine\ORM\Exception\NamedQueryNotFound;
|
||||
use Doctrine\ORM\Exception\ProxyClassesAlwaysRegenerating;
|
||||
use Doctrine\ORM\Exception\UnexpectedAssociationValue;
|
||||
use Doctrine\ORM\Exception\UnknownEntityNamespace;
|
||||
use Doctrine\ORM\Exception\UnrecognizedIdentifierFields;
|
||||
use Doctrine\ORM\Persisters\Exception\CantUseInOperatorOnCompositeKeys;
|
||||
use Doctrine\ORM\Persisters\Exception\InvalidOrientation;
|
||||
use Doctrine\ORM\Persisters\Exception\UnrecognizedField;
|
||||
use Doctrine\ORM\Repository\Exception\InvalidFindByCall;
|
||||
use Doctrine\ORM\Repository\Exception\InvalidMagicMethodCall;
|
||||
use Doctrine\ORM\Tools\Exception\NotSupported;
|
||||
use Exception;
|
||||
|
||||
use function get_debug_type;
|
||||
use function implode;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
@@ -26,8 +46,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function missingMappingDriverImpl()
|
||||
{
|
||||
return new self("It's a requirement to specify a Metadata Driver and pass it " .
|
||||
'to Doctrine\\ORM\\Configuration::setMetadataDriverImpl().');
|
||||
return MissingMappingDriverImplementation::create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,11 +58,11 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function namedQueryNotFound($queryName)
|
||||
{
|
||||
return new self('Could not find a named query by the name "' . $queryName . '"');
|
||||
return NamedQueryNotFound::fromName($queryName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Doctrine\ORM\Exception\NamedQueryNotFound
|
||||
* @deprecated Use Doctrine\ORM\Exception\NamedNativeQueryNotFound
|
||||
*
|
||||
* @param string $nativeQueryName
|
||||
*
|
||||
@@ -51,7 +70,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function namedNativeQueryNotFound($nativeQueryName)
|
||||
{
|
||||
return new self('Could not find a named native query by the name "' . $nativeQueryName . '"');
|
||||
return NamedNativeQueryNotFound::fromName($nativeQueryName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +82,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function unrecognizedField($field)
|
||||
{
|
||||
return new self(sprintf('Unrecognized field: %s', $field));
|
||||
return new UnrecognizedField(sprintf('Unrecognized field: %s', $field));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,7 +97,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function unexpectedAssociationValue($class, $association, $given, $expected)
|
||||
{
|
||||
return new self(sprintf('Found entity of type %s on association %s#%s, but expecting %s', $given, $class, $association, $expected));
|
||||
return UnexpectedAssociationValue::create($class, $association, $given, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,7 +110,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function invalidOrientation($className, $field)
|
||||
{
|
||||
return new self('Invalid order by orientation specified for ' . $className . '#' . $field);
|
||||
return InvalidOrientation::fromClassNameAndField($className, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +120,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function entityManagerClosed()
|
||||
{
|
||||
return new self('The EntityManager is closed.');
|
||||
return EntityManagerClosed::create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,7 +132,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function invalidHydrationMode($mode)
|
||||
{
|
||||
return new self(sprintf("'%s' is an invalid hydration mode.", $mode));
|
||||
return InvalidHydrationMode::fromMode($mode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,7 +142,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function mismatchedEventManager()
|
||||
{
|
||||
return new self('Cannot use different EventManager instances for EntityManager and Connection.');
|
||||
return MismatchedEventManager::create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,11 +154,11 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function findByRequiresParameter($methodName)
|
||||
{
|
||||
return new self("You need to pass a parameter to '" . $methodName . "'");
|
||||
return InvalidMagicMethodCall::onMissingParameter($methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Doctrine\ORM\Repository\Exception\InvalidFindByCall
|
||||
* @deprecated Doctrine\ORM\Repository\Exception\InvalidMagicMethodCall::becauseFieldNotFoundIn()
|
||||
*
|
||||
* @param string $entityName
|
||||
* @param string $fieldName
|
||||
@@ -149,10 +168,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function invalidMagicCall($entityName, $fieldName, $method)
|
||||
{
|
||||
return new self(
|
||||
"Entity '" . $entityName . "' has no field '" . $fieldName . "'. " .
|
||||
"You can therefore not call '" . $method . "' on the entities' repository"
|
||||
);
|
||||
return InvalidMagicMethodCall::becauseFieldNotFoundIn($entityName, $fieldName, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,10 +181,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function invalidFindByInverseAssociation($entityName, $associationFieldName)
|
||||
{
|
||||
return new self(
|
||||
"You cannot search for the association field '" . $entityName . '#' . $associationFieldName . "', " .
|
||||
'because it is the inverse side of an association. Find methods only work on owning side associations.'
|
||||
);
|
||||
return InvalidFindByCall::fromInverseSideUsage($entityName, $associationFieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +191,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function invalidResultCacheDriver()
|
||||
{
|
||||
return new self('Invalid result cache driver; it must implement Doctrine\\Common\\Cache\\Cache.');
|
||||
return InvalidResultCacheDriver::create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,7 +201,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function notSupported()
|
||||
{
|
||||
return new self('This behaviour is (currently) not supported by Doctrine 2');
|
||||
return NotSupported::create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +211,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function queryCacheNotConfigured()
|
||||
{
|
||||
return new self('Query Cache is not configured.');
|
||||
return QueryCacheNotConfigured::create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +221,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function metadataCacheNotConfigured()
|
||||
{
|
||||
return new self('Class Metadata Cache is not configured.');
|
||||
return MetadataCacheNotConfigured::create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,7 +231,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function queryCacheUsesNonPersistentCache(CacheDriver $cache)
|
||||
{
|
||||
return new self('Query Cache uses a non-persistent cache driver, ' . get_debug_type($cache) . '.');
|
||||
return QueryCacheUsesNonPersistentCache::fromDriver($cache);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,7 +241,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function metadataCacheUsesNonPersistentCache(CacheDriver $cache)
|
||||
{
|
||||
return new self('Metadata Cache uses a non-persistent cache driver, ' . get_debug_type($cache) . '.');
|
||||
return MetadataCacheUsesNonPersistentCache::fromDriver($cache);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,7 +251,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function proxyClassesAlwaysRegenerating()
|
||||
{
|
||||
return new self('Proxy Classes are always regenerating.');
|
||||
return ProxyClassesAlwaysRegenerating::create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,9 +263,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function unknownEntityNamespace($entityNamespaceAlias)
|
||||
{
|
||||
return new self(
|
||||
sprintf("Unknown Entity namespace alias '%s'.", $entityNamespaceAlias)
|
||||
);
|
||||
return UnknownEntityNamespace::fromNamespaceAlias($entityNamespaceAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,11 +275,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function invalidEntityRepository($className)
|
||||
{
|
||||
return new self(sprintf(
|
||||
"Invalid repository class '%s'. It must be a %s.",
|
||||
$className,
|
||||
ObjectRepository::class
|
||||
));
|
||||
return InvalidEntityRepository::fromClassName($className);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,7 +288,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function missingIdentifierField($className, $fieldName)
|
||||
{
|
||||
return new self(sprintf('The identifier %s is missing for a query of %s', $fieldName, $className));
|
||||
return MissingIdentifierField::fromFieldAndClass($fieldName, $className);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,10 +301,7 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function unrecognizedIdentifierFields($className, $fieldNames)
|
||||
{
|
||||
return new self(
|
||||
"Unrecognized identifier fields: '" . implode("', '", $fieldNames) . "' " .
|
||||
"are not present on class '" . $className . "'."
|
||||
);
|
||||
return UnrecognizedIdentifierFields::fromClassAndFieldNames($className, $fieldNames);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,6 +311,6 @@ class ORMException extends Exception
|
||||
*/
|
||||
public static function cantUseInOperatorOnCompositeKeys()
|
||||
{
|
||||
return new self("Can't use IN operator on entities that have composite keys.");
|
||||
return CantUseInOperatorOnCompositeKeys::create();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\Selectable;
|
||||
use Doctrine\ORM\Internal\CriteriaOrderings;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use ReturnTypeWillChange;
|
||||
use RuntimeException;
|
||||
@@ -41,6 +42,8 @@ use function spl_object_id;
|
||||
*/
|
||||
final class PersistentCollection extends AbstractLazyCollection implements Selectable
|
||||
{
|
||||
use CriteriaOrderings;
|
||||
|
||||
/**
|
||||
* A snapshot of the collection at the moment it was fetched from the database.
|
||||
* This is used to create a diff of the collection at commit time.
|
||||
@@ -409,11 +412,6 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
|
||||
return parent::containsKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @template TMaybeContained
|
||||
*/
|
||||
public function contains($element): bool
|
||||
{
|
||||
if (! $this->initialized && $this->getMapping()['fetch'] === ClassMetadata::FETCH_EXTRA_LAZY) {
|
||||
@@ -671,7 +669,9 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
|
||||
|
||||
$criteria = clone $criteria;
|
||||
$criteria->where($expression);
|
||||
$criteria->orderBy($criteria->getOrderings() ?: $association['orderBy'] ?? []);
|
||||
$criteria->orderBy(self::mapToOrderEnumIfAvailable(
|
||||
self::getCriteriaOrderings($criteria) ?: $association['orderBy'] ?? []
|
||||
));
|
||||
|
||||
$persister = $this->getUnitOfWork()->getEntityPersister($association['targetEntity']);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use BadMethodCallException;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\Expr\Comparison;
|
||||
use Doctrine\DBAL\Exception as DBALException;
|
||||
use Doctrine\ORM\Internal\CriteriaOrderings;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Persisters\SqlValueVisitor;
|
||||
@@ -30,6 +31,8 @@ use function sprintf;
|
||||
*/
|
||||
class ManyToManyPersister extends AbstractCollectionPersister
|
||||
{
|
||||
use CriteriaOrderings;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -745,7 +748,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
|
||||
|
||||
private function getOrderingSql(Criteria $criteria, ClassMetadata $targetClass): string
|
||||
{
|
||||
$orderings = $criteria->getOrderings();
|
||||
$orderings = self::getCriteriaOrderings($criteria);
|
||||
if ($orderings) {
|
||||
$orderBy = [];
|
||||
foreach ($orderings as $name => $direction) {
|
||||
|
||||
@@ -8,13 +8,18 @@ use BadMethodCallException;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\DBAL\Exception as DBALException;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\ORM\EntityNotFoundException;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\ORM\PersistentCollection;
|
||||
use Doctrine\ORM\Utility\PersisterHelper;
|
||||
|
||||
use function array_fill;
|
||||
use function array_keys;
|
||||
use function array_merge;
|
||||
use function array_reverse;
|
||||
use function array_values;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function is_int;
|
||||
use function is_string;
|
||||
@@ -166,7 +171,11 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
throw new BadMethodCallException('Filtering a collection by Criteria is not supported by this CollectionPersister.');
|
||||
}
|
||||
|
||||
/** @throws DBALException */
|
||||
/**
|
||||
* @throws DBALException
|
||||
* @throws EntityNotFoundException
|
||||
* @throws MappingException
|
||||
*/
|
||||
private function deleteEntityCollection(PersistentCollection $collection): int
|
||||
{
|
||||
$mapping = $collection->getMapping();
|
||||
@@ -186,6 +195,16 @@ class OneToManyPersister extends AbstractCollectionPersister
|
||||
$statement = 'DELETE FROM ' . $this->quoteStrategy->getTableName($targetClass, $this->platform)
|
||||
. ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
|
||||
|
||||
if ($targetClass->isInheritanceTypeSingleTable()) {
|
||||
$discriminatorColumn = $targetClass->getDiscriminatorColumn();
|
||||
$discriminatorValues = $targetClass->discriminatorValue ? [$targetClass->discriminatorValue] : array_keys($targetClass->discriminatorMap);
|
||||
$statement .= ' AND ' . $discriminatorColumn['name'] . ' IN (' . implode(', ', array_fill(0, count($discriminatorValues), '?')) . ')';
|
||||
foreach ($discriminatorValues as $discriminatorValue) {
|
||||
$parameters[] = $discriminatorValue;
|
||||
$types[] = $discriminatorColumn['type'];
|
||||
}
|
||||
}
|
||||
|
||||
$numAffected = $this->conn->executeStatement($statement, $parameters, $types);
|
||||
|
||||
assert(is_int($numAffected));
|
||||
|
||||
@@ -15,6 +15,7 @@ use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Internal\CriteriaOrderings;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\ORM\Mapping\MappingException;
|
||||
use Doctrine\ORM\Mapping\QuoteStrategy;
|
||||
@@ -93,6 +94,7 @@ use function trim;
|
||||
*/
|
||||
class BasicEntityPersister implements EntityPersister
|
||||
{
|
||||
use CriteriaOrderings;
|
||||
use LockSqlHelper;
|
||||
|
||||
/** @var array<string,string> */
|
||||
@@ -830,17 +832,42 @@ class BasicEntityPersister implements EntityPersister
|
||||
|
||||
$computedIdentifier = [];
|
||||
|
||||
/** @var array<string,mixed>|null $sourceEntityData */
|
||||
$sourceEntityData = null;
|
||||
|
||||
// TRICKY: since the association is specular source and target are flipped
|
||||
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
|
||||
if (! isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name,
|
||||
$sourceKeyColumn
|
||||
);
|
||||
}
|
||||
// The likely case here is that the column is a join column
|
||||
// in an association mapping. However, there is no guarantee
|
||||
// at this point that a corresponding (generally identifying)
|
||||
// association has been mapped in the source entity. To handle
|
||||
// this case we directly reference the column-keyed data used
|
||||
// to initialize the source entity before throwing an exception.
|
||||
$resolvedSourceData = false;
|
||||
if (! isset($sourceEntityData)) {
|
||||
$sourceEntityData = $this->em->getUnitOfWork()->getOriginalEntityData($sourceEntity);
|
||||
}
|
||||
|
||||
$computedIdentifier[$targetClass->getFieldForColumn($targetKeyColumn)] =
|
||||
$sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
if (isset($sourceEntityData[$sourceKeyColumn])) {
|
||||
$dataValue = $sourceEntityData[$sourceKeyColumn];
|
||||
if ($dataValue !== null) {
|
||||
$resolvedSourceData = true;
|
||||
$computedIdentifier[$targetClass->getFieldForColumn($targetKeyColumn)] =
|
||||
$dataValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $resolvedSourceData) {
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name,
|
||||
$sourceKeyColumn
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$computedIdentifier[$targetClass->getFieldForColumn($targetKeyColumn)] =
|
||||
$sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
}
|
||||
}
|
||||
|
||||
$targetEntity = $this->load($computedIdentifier, null, $assoc);
|
||||
@@ -884,7 +911,7 @@ class BasicEntityPersister implements EntityPersister
|
||||
*/
|
||||
public function loadCriteria(Criteria $criteria)
|
||||
{
|
||||
$orderBy = $criteria->getOrderings();
|
||||
$orderBy = self::getCriteriaOrderings($criteria);
|
||||
$limit = $criteria->getMaxResults();
|
||||
$offset = $criteria->getFirstResult();
|
||||
$query = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy);
|
||||
|
||||
@@ -250,6 +250,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
|
||||
|
||||
// If the database platform supports FKs, just
|
||||
// delete the row from the root table. Cascades do the rest.
|
||||
// @phpstan-ignore method.deprecated
|
||||
if ($this->platform->supportsForeignKeyConstraints()) {
|
||||
$rootClass = $this->em->getClassMetadata($this->class->rootEntityName);
|
||||
$rootTable = $this->quoteStrategy->getTableName($rootClass, $this->platform);
|
||||
|
||||
@@ -173,6 +173,7 @@ EOPHP;
|
||||
$this->isLazyGhostObjectEnabled = false;
|
||||
|
||||
$proxyGenerator = new ProxyGenerator($proxyDir, $proxyNs);
|
||||
// @phpstan-ignore classConstant.deprecatedInterface
|
||||
$proxyGenerator->setPlaceholder('baseProxyInterface', LegacyProxy::class);
|
||||
|
||||
parent::__construct($proxyGenerator, $em->getMetadataFactory(), $autoGenerate);
|
||||
@@ -354,17 +355,16 @@ EOPHP;
|
||||
/**
|
||||
* Creates a closure capable of initializing a proxy
|
||||
*
|
||||
* @return Closure(InternalProxy, InternalProxy):void
|
||||
* @return Closure(InternalProxy, array):void
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
*/
|
||||
private function createLazyInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister, IdentifierFlattener $identifierFlattener): Closure
|
||||
{
|
||||
return static function (InternalProxy $proxy, InternalProxy $original) use ($entityPersister, $classMetadata, $identifierFlattener): void {
|
||||
$identifier = $classMetadata->getIdentifierValues($original);
|
||||
$entity = $entityPersister->loadById($identifier, $original);
|
||||
return static function (InternalProxy $proxy, array $identifier) use ($entityPersister, $classMetadata, $identifierFlattener): void {
|
||||
$original = $entityPersister->loadById($identifier);
|
||||
|
||||
if ($entity === null) {
|
||||
if ($original === null) {
|
||||
throw EntityNotFoundException::fromClassNameAndIdentifier(
|
||||
$classMetadata->getName(),
|
||||
$identifierFlattener->flattenIdentifier($classMetadata, $identifier)
|
||||
@@ -378,11 +378,11 @@ EOPHP;
|
||||
$class = $entityPersister->getClassMetadata();
|
||||
|
||||
foreach ($class->getReflectionProperties() as $property) {
|
||||
if (! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) {
|
||||
if (isset($identifier[$property->name]) || ! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$property->setValue($proxy, $property->getValue($entity));
|
||||
$property->setValue($proxy, $property->getValue($original));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -468,8 +468,8 @@ EOPHP;
|
||||
$identifierFields = array_intersect_key($class->getReflectionProperties(), $identifiers);
|
||||
|
||||
$proxyFactory = Closure::bind(static function (array $identifier) use ($initializer, $skippedProperties, $identifierFields, $className): InternalProxy {
|
||||
$proxy = self::createLazyGhost(static function (InternalProxy $object) use ($initializer, &$proxy): void {
|
||||
$initializer($object, $proxy);
|
||||
$proxy = self::createLazyGhost(static function (InternalProxy $object) use ($initializer, $identifier): void {
|
||||
$initializer($object, $identifier);
|
||||
}, $skippedProperties);
|
||||
|
||||
foreach ($identifierFields as $idField => $reflector) {
|
||||
|
||||
+32
-3
@@ -18,6 +18,8 @@ use Doctrine\ORM\Query\AST\DeleteStatement;
|
||||
use Doctrine\ORM\Query\AST\SelectStatement;
|
||||
use Doctrine\ORM\Query\AST\UpdateStatement;
|
||||
use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
|
||||
use Doctrine\ORM\Query\Exec\SqlFinalizer;
|
||||
use Doctrine\ORM\Query\OutputWalker;
|
||||
use Doctrine\ORM\Query\Parameter;
|
||||
use Doctrine\ORM\Query\ParameterTypeInferer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
@@ -33,6 +35,7 @@ use function assert;
|
||||
use function count;
|
||||
use function get_debug_type;
|
||||
use function in_array;
|
||||
use function is_a;
|
||||
use function is_int;
|
||||
use function ksort;
|
||||
use function md5;
|
||||
@@ -196,7 +199,7 @@ class Query extends AbstractQuery
|
||||
*/
|
||||
public function getSQL()
|
||||
{
|
||||
return $this->parse()->getSqlExecutor()->getSqlStatements();
|
||||
return $this->getSqlExecutor()->getSqlStatements();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,7 +288,7 @@ class Query extends AbstractQuery
|
||||
*/
|
||||
protected function _doExecute()
|
||||
{
|
||||
$executor = $this->parse()->getSqlExecutor();
|
||||
$executor = $this->getSqlExecutor();
|
||||
|
||||
if ($this->_queryCacheProfile) {
|
||||
$executor->setQueryCacheProfile($this->_queryCacheProfile);
|
||||
@@ -344,6 +347,7 @@ class Query extends AbstractQuery
|
||||
|
||||
$cache = method_exists(QueryCacheProfile::class, 'getResultCache')
|
||||
? $this->_queryCacheProfile->getResultCache()
|
||||
// @phpstan-ignore method.deprecated
|
||||
: $this->_queryCacheProfile->getResultCacheDriver();
|
||||
|
||||
assert($cache !== null);
|
||||
@@ -812,11 +816,31 @@ class Query extends AbstractQuery
|
||||
{
|
||||
ksort($this->_hints);
|
||||
|
||||
if (! $this->hasHint(self::HINT_CUSTOM_OUTPUT_WALKER)) {
|
||||
// Assume Parser will create the SqlOutputWalker; save is_a call, which might trigger a class load
|
||||
$firstAndMaxResult = '';
|
||||
} else {
|
||||
$outputWalkerClass = $this->getHint(self::HINT_CUSTOM_OUTPUT_WALKER);
|
||||
if (is_a($outputWalkerClass, OutputWalker::class, true)) {
|
||||
$firstAndMaxResult = '';
|
||||
} else {
|
||||
Deprecation::trigger(
|
||||
'doctrine/orm',
|
||||
'https://github.com/doctrine/orm/pull/11188/',
|
||||
'Your output walker class %s should implement %s in order to provide a %s. This also means the output walker should not use the query firstResult/maxResult values, which should be read from the query by the SqlFinalizer only.',
|
||||
$outputWalkerClass,
|
||||
OutputWalker::class,
|
||||
SqlFinalizer::class
|
||||
);
|
||||
$firstAndMaxResult = '&firstResult=' . $this->firstResult . '&maxResult=' . $this->maxResults;
|
||||
}
|
||||
}
|
||||
|
||||
return md5(
|
||||
$this->getDQL() . serialize($this->_hints) .
|
||||
'&platform=' . get_debug_type($this->getEntityManager()->getConnection()->getDatabasePlatform()) .
|
||||
($this->_em->hasFilters() ? $this->_em->getFilters()->getHash() : '') .
|
||||
'&firstResult=' . $this->firstResult . '&maxResult=' . $this->maxResults .
|
||||
$firstAndMaxResult .
|
||||
'&hydrationMode=' . $this->_hydrationMode . '&types=' . serialize($this->parsedTypes) . 'DOCTRINE_QUERY_CACHE_SALT'
|
||||
);
|
||||
}
|
||||
@@ -835,4 +859,9 @@ class Query extends AbstractQuery
|
||||
|
||||
$this->state = self::STATE_DIRTY;
|
||||
}
|
||||
|
||||
private function getSqlExecutor(): AbstractSqlExecutor
|
||||
{
|
||||
return $this->parse()->prepareSqlExecutor($this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\SimpleArithmeticExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
/**
|
||||
* "ABS" "(" SimpleArithmeticExpression ")"
|
||||
@@ -30,11 +30,11 @@ class AbsFunction extends FunctionNode
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
/**
|
||||
* "BIT_AND" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
|
||||
@@ -36,13 +36,13 @@ class BitAndFunction extends FunctionNode
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstArithmetic = $parser->ArithmeticPrimary();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$parser->match(TokenType::T_COMMA);
|
||||
$this->secondArithmetic = $parser->ArithmeticPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
/**
|
||||
* "BIT_OR" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
|
||||
@@ -36,13 +36,13 @@ class BitOrFunction extends FunctionNode
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstArithmetic = $parser->ArithmeticPrimary();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$parser->match(TokenType::T_COMMA);
|
||||
$this->secondArithmetic = $parser->ArithmeticPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
/**
|
||||
* "CONCAT" "(" StringPrimary "," StringPrimary {"," StringPrimary }* ")"
|
||||
@@ -42,22 +42,22 @@ class ConcatFunction extends FunctionNode
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstStringPrimary = $parser->StringPrimary();
|
||||
$this->concatExpressions[] = $this->firstStringPrimary;
|
||||
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$parser->match(TokenType::T_COMMA);
|
||||
|
||||
$this->secondStringPrimary = $parser->StringPrimary();
|
||||
$this->concatExpressions[] = $this->secondStringPrimary;
|
||||
|
||||
while ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
while ($parser->getLexer()->isNextToken(TokenType::T_COMMA)) {
|
||||
$parser->match(TokenType::T_COMMA);
|
||||
$this->concatExpressions[] = $parser->StringPrimary();
|
||||
}
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
/**
|
||||
* "CURRENT_DATE"
|
||||
@@ -24,8 +24,8 @@ class CurrentDateFunction extends FunctionNode
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
/**
|
||||
* "CURRENT_TIME"
|
||||
@@ -24,8 +24,8 @@ class CurrentTimeFunction extends FunctionNode
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
/**
|
||||
* "CURRENT_TIMESTAMP"
|
||||
@@ -24,8 +24,8 @@ class CurrentTimestampFunction extends FunctionNode
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ declare(strict_types=1);
|
||||
namespace Doctrine\ORM\Query\AST\Functions;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Node;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\QueryException;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
use Doctrine\ORM\Query\TokenType;
|
||||
|
||||
use function strtolower;
|
||||
|
||||
@@ -84,15 +84,15 @@ class DateAddFunction extends FunctionNode
|
||||
/** @inheritDoc */
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$parser->match(TokenType::T_IDENTIFIER);
|
||||
$parser->match(TokenType::T_OPEN_PARENTHESIS);
|
||||
|
||||
$this->firstDateExpression = $parser->ArithmeticPrimary();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$parser->match(TokenType::T_COMMA);
|
||||
$this->intervalExpression = $parser->ArithmeticPrimary();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$parser->match(TokenType::T_COMMA);
|
||||
$this->unit = $parser->StringPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user