Compare commits

...

63 Commits

Author SHA1 Message Date
Grégoire Paris
01187c9260 Remove trailing whitespaces (#8360)
Stylistically, it's not great to have them, but more importantly, the
latest symfony/yaml version has issues with trailing whitespaces.
2020-12-03 09:52:14 +01:00
Benjamin Eberlei
404edd418b [GH-8229] Prevent Illegal Inheritance Override (#8348)
* [GH-8229] Prevent AttributeOverride on fields from entities, only allowed for MappedSuperclass

* [GH-8229] Prevent AssociationOverride on fields from entities, only allowed for MappedSuperclass

* Revert "Fix SQL alias generation regression for simple inheritance (#8329)"

This reverts commit f4ebded63c.

* [GH-8229] Finalize checks for illegal attribute/assocation overrides.

* [GH-8229] Revert ccae8f7176 PR #8234

* [GH-8229] Update documentation to clarify only mapped superclass or trait works with overrides

* [GH-8229] Fix style violations introduced by revert

* [GH-8229] Fix style violations introduced by revert

* [GH-8229] Temporarily disable the exception until 2.8.

* Make phpcs happy
2020-11-25 23:04:56 +01:00
Claudio Zizza
011d3c21eb Update functionality of code examples (#8336) 2020-11-24 22:39:42 +01:00
Roma
b1ac293a50 Add missing backtick in rst markup (#8335) 2020-11-10 20:37:36 +01:00
Romain Grégoire
f4ebded63c Fix SQL alias generation regression for simple inheritance (#8329)
This fixes a regression from 099c5b42e1.
Without the fix, "where part" in SQL is generated with incorrect aliases.
See https://github.com/doctrine/orm/issues/8229#issuecomment-722942180.
2020-11-10 10:53:01 +01:00
Grégoire Paris
385b5a2f80 Phpunit 8 (#8330)
* Revert to whitelist

coverage requires PHPunit 9, and we don't have that yet.

* Upgrade to PHPUnit 8

This unlocks PCOV usage for coverage

* Upload coverage files to Codecov
2020-11-07 19:41:15 +01:00
Benjamin Eberlei
fa6fe09647 Ignore composer.lock 2020-11-07 18:37:46 +01:00
Benjamin Eberlei
c270eba678 Start moving travis phpunit runs to Github actions. (#8317)
* Move PHPUnit runs from Travis to Github Actions

This removes all artifacts used for TravisCI testing and replaces them
with the existing infrastructure for Github Actions from DBAL component.

In addition some test changes were needed and triggered larger Coding
Style cleanups in 3 test files.

* Remove composer.lock and improve naming in CI workflow.
2020-11-07 18:11:42 +01:00
Michael Käfer
2f0eb95c90 Patch 1 (#8325)
* Update outdated doc parts

- The cache implementation moved from `Common` to `doctrine/cache`
- APCu is mor appropiate nowadays I guess
- AbstractQuery::useResultCache() is deprecated since 2.7

* Fix wrong argument

* Fix wrong arguments and remove useless line
2020-10-31 12:13:48 +01:00
Grégoire Paris
b13b2e8bab Upgrade doctrine/coding-standard (#8321)
* Use a classname that exists

Doctrine\ORM\Mapping\TableGenerator does not exist, only
Doctrine\ORM\Id\TableGenerator does.

* Upgrade doctrine/coding-standard

That library has a dependency on another library that requires composer
plugin API v1. Updating both libs allow to use Composer v2.

* Account for doctrine/reflection deprecation
2020-10-28 11:14:10 +01:00
Michael Voříšek
ca27cc3f72 Fix EOL of text files (#8310) 2020-10-17 19:04:42 +02:00
Laurent VOULLEMIER
5fde5801c1 Fix many typos (#8299)
- Some uppercase letters were used in the middle of sentence
- Some dots were missing
- There was two sentences with wrong or missing words
2020-10-13 21:52:04 +02:00
Thomas Landauer
18d96fcc02 Update working-with-indexed-associations.rst (#8298)
* Update working-with-indexed-associations.rst

Fixing broken link

* Update docs/en/tutorials/working-with-indexed-associations.rst

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2020-10-12 21:27:18 +02:00
Benjamin Eberlei
4d2908a065 Change <phpunit verbose="true" /> to false for better readability of test output. 2020-10-11 19:14:47 +02:00
Benjamin Eberlei
8d250f5921 Use SHELL_VERBOSITY=3 instead of LOG_LEVEL=DEBUG 2020-10-11 12:03:57 +02:00
Benjamin Eberlei
59fd9b5ea7 Change LOG_LEVEL to debug should expose more info from laminas/automatic-releases. 2020-10-11 00:17:52 +02:00
Benjamin Eberlei
8fcc70cfbe Change LOG_LEVEL to debug should expose more info from laminas/automatic-releases. 2020-10-11 00:14:35 +02:00
Grégoire Paris
7d84a49980 Setup automated release workflow (#8301) 2020-10-10 19:11:26 +02:00
Claudio Zizza
bb64fc953d Move website config to default branch (#8287)
Adds the website config to be compatible with the doctrine/doctrine-website#356 changes
2020-10-02 20:31:00 +02:00
orklah
e0eb82a3b1 psalm fixes (#8286) 2020-09-30 22:00:38 +02:00
orklah
79cdcde9ec rename parameters to match parents (#8284) 2020-09-26 20:24:11 +02:00
orklah
f4524a8bb0 Fix psalm errors and upgrade strictness (#8209)
* Fixes and improvements

* fix param type
2020-09-25 20:44:07 +02:00
Grégoire Paris
d810ea4111 Use inline literals over escaping (#8279)
Escaping underscores does not work as expected.
See https://www.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/dql-custom-walkers.html#modify-the-output-walker-to-generate-vendor-specific-sql
2020-09-22 20:10:05 +02:00
Michael Voříšek
107ba93d79 Convert CRLF to LF in test file (#8276)
* Convert CRLF to LF in test file
* fix cs
2020-09-21 22:51:49 +02:00
Guillaume Simon
706670215d Fix OrderByItem parser to proceed with SimpleArithmetic expression before function (#8277)
There is parser bug for OrderByItem(), where a function is detected
before a SimpleArithmeticExpression while it should be the reverse:
simple arithmetic expressions can start with a function too, and thus
they should be matched first if present.

This fix enables the use of expressions in sorting and with window
functions.
2020-09-20 18:56:57 +02:00
Yohann Durand
ab2b4987b3 Improve formatting (#8028) 2020-09-08 20:56:51 +02:00
Thomas Landauer
717ef9106c Update events.rst (#8257)
* Update events.rst

Improved code formatting

* Update docs/en/reference/events.rst

I was wondering myself what the `#` was about ;-)

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>

* Update events.rst

See https://github.com/doctrine/orm/pull/8257#discussion_r482305774

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2020-09-03 22:44:28 +02:00
Christoph Ziegenberg
ccae8f7176 Fix for bug #8229 (id column from parent class renamed in child class) (#8234)
This fixes problems with id columns defined in the parent class but renamed in the child class using an attribute override. Before this change always the child column name was used (which was not present in the parent class), now the correct column names are used for the parent table when creating inserts, joins and deletions for it.

Co-authored-by: Crossjoin <crossjoin@users.noreply.github.com>
2020-08-29 13:25:18 +02:00
Grégoire Paris
da18985aca Stop using the DBAL extension of PHPBench (#8252)
It has been removed, and the default XML storage driver is supposed to
be fine for our purposes.
2020-08-29 12:28:40 +02:00
Simon Podlipsky
1e2ed07731 Use consistent formatting in command line (#8238) 2020-08-12 08:38:00 +02:00
Grégoire Paris
424241f29c Use more accurate terminology (#8236)
I think this was a mistake when writing this documentation, and that the
original author meant to use attribute here, columns do not have
columns, they have attributes.
2020-08-09 22:48:52 +02:00
Grégoire Paris
8230afcde9 Fetch deeper
This is needed to preserve parent information and be able to find the
merge base with the head branch. The assumption here is that the common
ancestor can be found among the 10 parent commits.
2020-08-07 22:11:21 +02:00
Kirill Matasov
7cffba8743 Fix annotation in Expr 2020-08-07 22:11:21 +02:00
Benjamin Cremer
7e5fe79349 Change preferred cache driver for metadata and query caches (#8223)
See: https://twitter.com/lcobucci/status/1289087725694484481
2020-08-03 21:40:52 +02:00
njutn95
efd25484f4 Update aggregate-fields.rst (#8215)
Minor typo fix
2020-07-20 21:19:16 +02:00
Andreas Möller
271f3480c8 Fix: Typo (#8213) 2020-07-15 22:46:25 +02:00
orklah
aab589b596 add/fix more types (checked by psalm) (#8199)
* add/fix more psalm types

* remove inexistant SimpleEntityExpression

* Declare template implements for TreeWalkerChainIterator
2020-07-10 22:08:13 +02:00
orklah
190218b267 Change list() syntax to array destructuring (short list syntax) (#8204) 2020-07-07 22:02:34 +02:00
Benjamin Eberlei
181114f2c7 [GH-8106] Move test into existing QueryTest testcase to reduce surface. 2020-07-05 21:51:35 +02:00
tom93
3689b76a86 Fix QueryBuilder::getParameter() on parameter names with colons (#8107)
* Fix type errors

(partially cherry picked from commit 17e7c2a42e)

* Fix QueryBuilder::getParameter() on parameter names with colons

Fixes #8106.

Co-authored-by: Michael Moravec <mail@majkl578.cz>
2020-07-05 21:46:48 +02:00
Igor Pellegrini
75fe18ea5f Add alert to "avoid persisting detached entities" (#8109)
The alert is hidden into the code of ``EntityManager``,
while it's useful to be mentioned in the documentation.
2020-07-05 20:24:08 +02:00
Grégoire Paris
6c73a6b720 Infer return type information with Psalter (#8150)
These changes are a subset of changes done with vendor/bin/psalm --alter
--issues=LessSpecificReturnType
--allow-backwards-incompatible-changes=false
2020-07-05 20:15:39 +02:00
Benjamin Eberlei
775d91c2a3 [GH-8122] Move test from AbstractMappingDriverTest to ClassMetadataFactoryTest case 2020-07-05 20:11:01 +02:00
Gildas Quéméner
64c3f68734 Prohibits class typo in the discriminator map (#8122)
* Prevents incorrect table aliases to be generated

When a defined subclass has a case typo, the query builder will be lost
and will generate exotic table alias. This commit fixes the issue at the
root by prohibiting case typo in discriminator map.

See https://github.com/doctrine/orm/pull/8112 for the consequence of
such typo.

* Controls growing rate of the abstract test class

* Fixes incorrect test case

The Cube class must be autoloaded with the correct case, otherwise
composer autoloader will complain.

* Removes non architecture compliant code

See https://github.com/doctrine/orm/pull/8122/files#r423952247

* Ensures discriminator map is case sensitive
2020-07-05 19:48:38 +02:00
Mohamed Ettaki Talbi
2a2a0b2980 Remove unwanted period (#8198) 2020-07-02 08:36:18 +02:00
vladyslavstartsev
a438e90046 add dev files to .gitattribute (#8190)
those files probably are not used by end user of the lib
2020-06-19 13:48:45 +02:00
Nicolas Grekas
6a670d7d6d Allow using on PHP 7.1 with Composer 2 (#8184) 2020-06-18 23:05:13 +02:00
Grégoire Paris
765521d257 Use CodeCov instead of Scrutinizer (#8187)
* Document current branch status in the README

* Use CodeCov instead of Scrutinizer
2020-06-17 22:47:25 +02:00
Grégoire Paris
5ced62bf83 Run benchmark on PHP 7.4 (#8186)
phpbench recently dropped compatibilty with PHP 7.1
When this job was introduced, 7.1 was the latest version of PHP we
supported, so it makes sense to bump to 7.4 now.
See https://github.com/phpbench/phpbench/releases/tag/0.17.0
See e07c90df44
2020-06-17 22:06:42 +02:00
Alexander Berl
93867f8d77 TASK: Replace "Blacklist" example with "Banlist" (#8174) 2020-06-08 23:06:53 +02:00
Grégoire Paris
d95e03ba66 Allow doctrine/common 3 and doctrine/persistence 2 (#8158) 2020-05-26 18:03:49 +02:00
Robert Basic
825ceb6b7a Fix inline code example (#8153)
* Fix inline code example

* Remove extra backslash
2020-05-22 22:45:24 +02:00
orklah
de2e2a1d74 Add psalm types (#7989) 2020-05-18 21:48:28 +02:00
Grégoire Paris
6780a963f7 Migrate git-phpcs to Github actions (#8146) 2020-05-16 14:01:10 +02:00
Benjamin Eberlei
4d172e2591 Revert changes to embeddable mapping in 2.7 (#8138)
* Revert "Fix inherited embeddables and nesting after AnnotationDriver change #8006 (#8036)"

This reverts commit a9b6b72017.

* Revert "Make Embeddable not transient"

This reverts commit 58677c29b4.

* Housekeeping: CS fixes
2020-05-12 20:10:26 +02:00
Grégoire Paris
21a98234d0 Static analysis with Psalm (#8116)
* Remove useless ternaries

If these expressions are truish inside the condition, they will still be
truish inside the if.

* Describe properties more accurately

These are not objects, they are strings holding class names for classes
that implement TreeWalker.

* Remove duplicate key

Comparison::IS and Comparison::EQ are the same. I chose to remove IS
because it does not seem to exist anymore on master

* Remove unwanted . before = operator

This worked, but makes no sense.

* Setup static analysis with Psalm

* Move PHPStan to Github actions
2020-05-11 23:06:46 +02:00
Grégoire Paris
8a9954e46c Address deprecations from persistence (#7953)
A backwards-compatibility layer has been added to persistence to help
consumers move to the new namespacing. It is based on class aliases,
which means the type declaration changes should not be a BC-break: types
are the same.
See https://github.com/doctrine/persistence/pull/71

This means:
- using the new namespaces
- adding autoload calls for new types to types that may be extended and
use persistence types in type declarations of non-constructor methods,
so that signature compatibility is recognized by old versions of php.
More details on this at
https://dev.to/greg0ire/how-to-deprecate-a-type-in-php-48cf
2020-05-07 08:35:39 +02:00
Grzesiek
527fff53cc removed repository class from metadata (#8125)
The annotation is required only in the next chapter of the tutorial, specifically the "Entity Repositories"
2020-05-03 21:58:20 +02:00
Maks Rafalko
70fb1ecd78 Warn users about performance issues with DateTime objects in setParameter() (#8114) 2020-04-25 22:16:17 +02:00
Jeroen van den Heuvel
73ec483e9d Convert PHP to SQL for new object expression (#8062) 2020-04-16 23:01:43 +02:00
Mathieu
8d67eec812 Fix JoinColumn documentation (#7966) 2020-03-30 21:33:13 +02:00
Vincent Langlet
a418cf6418 Remove TODO (#8078) 2020-03-30 20:06:04 +02:00
Arne
6138afdca9 [Docs] Make clear that calling remove() detaches the object (#8081)
I changed a relationship from eager to lazy loading which broker the behaviour of my application in regards to object removal. It was not clear for me that removing an object detaches it and subsequent calls like contains() in a OneToMany relationship with the object scheduled for removal will return false afterwards.
2020-03-27 19:42:39 +01:00
634 changed files with 3301 additions and 5182 deletions

49
.doctrine-project.json Normal file
View File

@@ -0,0 +1,49 @@
{
"active": true,
"name": "Object Relational Mapper",
"shortName": "ORM",
"slug": "orm",
"docsSlug": "doctrine-orm",
"versions": [
{
"name": "3.0",
"branchName": "master",
"slug": "latest",
"upcoming": true
},
{
"name": "2.8",
"branchName": "2.8.x",
"slug": "2.8",
"upcoming": true
},
{
"name": "2.7",
"branchName": "2.7",
"slug": "2.7",
"current": true,
"aliases": [
"current",
"stable"
]
},
{
"name": "2.6",
"branchName": "2.6",
"slug": "2.6",
"maintained": false
},
{
"name": "2.5",
"branchName": "2.5",
"slug": "2.5",
"maintained": false
},
{
"name": "2.4",
"branchName": "2.4",
"slug": "2.4",
"maintained": false
}
]
}

4
.gitattributes vendored
View File

@@ -1,5 +1,6 @@
/tests export-ignore
/tools export-ignore
/.github export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.gitmodules export-ignore
@@ -11,3 +12,6 @@ CONTRIBUTING.md export-ignore
phpunit.xml.dist export-ignore
run-all.sh export-ignore
phpcs.xml.dist export-ignore
phpbench.json export-ignore
phpstan.neon export-ignore
psalm.xml export-ignore

46
.github/workflows/coding-standard.yml vendored Normal file
View File

@@ -0,0 +1,46 @@
name: Static Analysis
on:
pull_request:
jobs:
coding-standards:
name: "Coding Standards"
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 10
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: "cs2pr"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
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 --no-suggest"
- name: "Install git-phpcs"
run: "wget https://github.com/diff-sniffer/git/releases/download/0.3.2/git-phpcs.phar"
- name: "Fetch head branch"
run: "git remote set-branches --add origin $GITHUB_BASE_REF && git fetch origin $GITHUB_BASE_REF"
- name: "Run git-phpcs"
run: "php git-phpcs.phar origin/$GITHUB_BASE_REF...$GITHUB_SHA --report=checkstyle | cs2pr"

View File

@@ -0,0 +1,284 @@
name: "Continuous Integration"
on:
pull_request:
push:
env:
fail-fast: true
jobs:
phpunit-smoke-check:
name: "PHPUnit with SQLite"
runs-on: "ubuntu-20.04"
strategy:
matrix:
php-version:
- "7.2"
- "7.3"
- "7.4"
deps:
- "normal"
include:
- deps: "low"
php-version: "7.3"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
extensions: "pdo, pdo_sqlite"
coverage: "pcov"
ini-values: "zend.assertions=1"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v2"
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 --no-suggest"
if: "${{ matrix.deps == 'normal' }}"
- name: "Install lowest possible dependencies with composer"
run: "composer update --no-interaction --no-progress --no-suggest --prefer-dist --prefer-lowest"
if: "${{ matrix.deps == 'low' }}"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite.xml --coverage-clover=coverage-no-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 0
- name: "Run PHPUnit with Second Level Cache"
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite.xml --exclude-group performance,non-cacheable,locking_functional --coverage-clover=coverage-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 1
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
with:
name: "phpunit-sqlite-${{ matrix.deps }}-${{ matrix.php-version }}-coverage"
path: "coverage*.xml"
phpunit-postgres:
name: "PHPUnit with PostgreSQL"
runs-on: "ubuntu-20.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "7.4"
postgres-version:
- "9.6"
- "13"
services:
postgres:
image: "postgres:${{ matrix.postgres-version }}"
env:
POSTGRES_PASSWORD: "postgres"
options: >-
--health-cmd "pg_isready"
ports:
- "5432:5432"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
coverage: "pcov"
ini-values: "zend.assertions=1"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v2"
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 --no-suggest"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
with:
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-coverage"
path: "coverage.xml"
phpunit-mariadb:
name: "PHPUnit with MariaDB"
runs-on: "ubuntu-20.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "7.4"
mariadb-version:
- "10.5"
extension:
- "mysqli"
- "pdo_mysql"
services:
mariadb:
image: "mariadb:${{ matrix.mariadb-version }}"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: "doctrine_tests"
options: >-
--health-cmd "mysqladmin ping --silent"
ports:
- "3306:3306"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
coverage: "pcov"
ini-values: "zend.assertions=1"
extensions: "${{ matrix.extension }}"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v2"
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 --no-suggest"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
with:
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-coverage"
path: "coverage.xml"
phpunit-mysql:
name: "PHPUnit with MySQL"
runs-on: "ubuntu-20.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "7.4"
mysql-version:
- "5.7"
- "8.0"
extension:
- "mysqli"
- "pdo_mysql"
services:
mysql:
image: "mysql:${{ matrix.mysql-version }}"
options: >-
--health-cmd "mysqladmin ping --silent"
-e MYSQL_ALLOW_EMPTY_PASSWORD=yes
-e MYSQL_DATABASE=doctrine_tests
ports:
- "3306:3306"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
coverage: "pcov"
ini-values: "zend.assertions=1"
extensions: "${{ matrix.extension }}"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v2"
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 --no-suggest"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage-no-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 0
- name: "Run PHPUnit with Second Level Cache"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --exclude-group performance,non-cacheable,locking_functional --coverage-clover=coverage-no-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 1
- name: "Upload coverage files"
uses: "actions/upload-artifact@v2"
with:
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-coverage"
path: "coverage*.xml"
upload_coverage:
name: "Upload coverage to Codecov"
runs-on: "ubuntu-20.04"
needs:
- "phpunit-smoke-check"
- "phpunit-postgres"
- "phpunit-mariadb"
- "phpunit-mysql"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 2
- name: "Download coverage files"
uses: "actions/download-artifact@v2"
with:
path: "reports"
- name: "Upload to Codecov"
uses: "codecov/codecov-action@v1"
with:
directory: reports

View File

@@ -0,0 +1,56 @@
name: "Automatic Releases"
on:
milestone:
types:
- "closed"
jobs:
release:
name: "Git tag, release & create merge-up PR"
runs-on: "ubuntu-20.04"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
- name: "Release"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:release"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
"SHELL_VERBOSITY": "3"
- name: "Create Merge-Up Pull Request"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:create-merge-up-pull-request"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create and/or Switch to new Release Branch"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:switch-default-branch-to-next-minor"
env:
"GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create new milestones"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:create-milestones"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}

70
.github/workflows/static-analysis.yml vendored Normal file
View File

@@ -0,0 +1,70 @@
name: Static Analysis
on:
pull_request:
jobs:
static-analysis-phpstan:
name: "PHPStan"
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout code"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: cs2pr
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
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-progress --no-suggest --no-interaction --prefer-dist"
- name: "Run a static analysis with phpstan/phpstan"
run: "php vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr"
static-analysis-psalm:
name: "Psalm"
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout code"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v1"
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 --no-suggest"
- name: "Run a static analysis with vimeo/psalm"
run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"

2
.gitignore vendored
View File

@@ -14,3 +14,5 @@ lib/Doctrine/DBAL
vendor/
/tests/Doctrine/Performance/history.db
/.phpcs-cache
composer.lock
/.phpunit.result.cache

View File

@@ -1,34 +0,0 @@
build:
nodes:
analysis:
environment:
php:
version: 7.1
cache:
disabled: false
directories:
- ~/.composer/cache
project_setup:
override: true
tests:
override:
- php-scrutinizer-run
before_commands:
- "composer install --no-dev --prefer-source"
tools:
external_code_coverage:
timeout: 3600
filter:
excluded_paths:
- docs
- tools
build_failure_conditions:
- 'elements.rating(<= C).new.exists' # No new classes/methods with a rating of C or worse allowed
- 'issues.severity(>= MAJOR).new.exists' # New issues of major or higher severity
- 'project.metric_change("scrutinizer.test_coverage", < 0)' # Code Coverage decreased from previous inspection
- 'patches.label("Unused Use Statements").new.exists' # No new unused imports patches allowed

View File

@@ -1,131 +0,0 @@
dist: trusty
sudo: false
language: php
php:
- 7.1
- 7.2
- 7.3
- 7.4
env:
- DB=sqlite
- DB=mysql
- DB=pgsql
before_install:
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{,.disabled} || echo "xdebug not available"
- composer self-update
install: travis_retry composer validate --strict && composer update --prefer-dist
script:
- if [[ "$DB" == "mysql" || "$DB" == "mariadb" ]]; then mysql -e "CREATE SCHEMA doctrine_tests; GRANT ALL PRIVILEGES ON doctrine_tests.* to travis@'%'"; fi
- ENABLE_SECOND_LEVEL_CACHE=0 ./vendor/bin/phpunit -v -c tests/travis/$DB.travis.xml
- ENABLE_SECOND_LEVEL_CACHE=1 ./vendor/bin/phpunit -v -c tests/travis/$DB.travis.xml --exclude-group performance,non-cacheable,locking_functional
jobs:
include:
- stage: Test
env: DB=mariadb
addons:
mariadb: 10.1
- stage: Test
dist: xenial
env: DB=mysql MYSQL_VERSION=5.7
php: 7.1
services:
- mysql
before_script:
- ./tests/travis/install-mysql-$MYSQL_VERSION.sh
sudo: required
- stage: Test
dist: xenial
env: DB=mysql MYSQL_VERSION=5.7
php: 7.2
services:
- mysql
before_script:
- ./tests/travis/install-mysql-$MYSQL_VERSION.sh
sudo: required
- stage: Test
dist: xenial
env: DB=mysql MYSQL_VERSION=5.7
php: 7.4
services:
- mysql
before_script:
- ./tests/travis/install-mysql-$MYSQL_VERSION.sh
sudo: required
- stage: Test
env: DB=sqlite DEPENDENCIES=low
install: travis_retry composer update --prefer-dist --prefer-lowest
- stage: Test
if: type = cron
php: 7.3
env: DB=sqlite DEV_DEPENDENCIES
install:
- composer config minimum-stability dev
- travis_retry composer update --prefer-dist
- stage: Test
env: DB=sqlite COVERAGE
before_script:
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{.disabled,}
- if [[ ! $(php -m | grep -si xdebug) ]]; then echo "xdebug required for coverage"; exit 1; fi
script:
- ENABLE_SECOND_LEVEL_CACHE=0 ./vendor/bin/phpunit -v -c tests/travis/$DB.travis.xml --coverage-clover ./build/logs/clover.xml
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml
- stage: Code Quality
env: DB=none STATIC_ANALYSIS
php: 7.4
install: travis_retry composer install --prefer-dist
before_script:
- echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- echo "extension=redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- travis_retry composer require --dev --prefer-dist --prefer-stable phpstan/phpstan:^0.9
script: vendor/bin/phpstan analyse -l 1 -c phpstan.neon lib
- stage: Code Quality
env: DB=none BENCHMARK
before_script: wget https://phpbench.github.io/phpbench/phpbench.phar https://phpbench.github.io/phpbench/phpbench.phar.pubkey
script: php phpbench.phar run -l dots --report=default
- stage: Code Quality
if: NOT type = pull_request
env: DB=none CODING_STANDARDS
php: 7.4
install: travis_retry composer install --prefer-dist
script:
- ./vendor/bin/phpcs
- stage: Code Quality
if: type = pull_request
env: DB=none PULL_REQUEST_CODING_STANDARDS
php: 7.1
install: travis_retry composer install --prefer-dist
script:
- |
if [ $TRAVIS_BRANCH != "master" ]; then
git remote set-branches --add origin $TRAVIS_BRANCH;
git fetch origin $TRAVIS_BRANCH;
fi
- git merge-base origin/$TRAVIS_BRANCH $TRAVIS_PULL_REQUEST_SHA || git fetch origin +refs/pull/$TRAVIS_PULL_REQUEST/merge --unshallow
- wget https://github.com/diff-sniffer/git/releases/download/0.2.0/git-phpcs.phar
- php git-phpcs.phar origin/$TRAVIS_BRANCH...$TRAVIS_PULL_REQUEST_SHA
allow_failures:
- stage: Code Quality
env: DB=none CODING_STANDARDS
cache:
directories:
- $HOME/.composer/cache

View File

@@ -1,7 +1,7 @@
| [Master][Master] | [2.5][2.5] |
| [Master][Master] | [2.7][2.7] |
|:----------------:|:----------:|
| [![Build status][Master image]][Master] | [![Build status][2.5 image]][2.5] |
| [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.5 coverage image]][2.5 coverage] |
| [![Build status][Master image]][Master] | [![Build status][2.7 image]][2.7] |
| [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.7 coverage image]][2.7 coverage] |
Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
@@ -18,9 +18,9 @@ without requiring unnecessary code duplication.
[Master image]: https://img.shields.io/travis/doctrine/orm/master.svg?style=flat-square
[Master]: https://travis-ci.org/doctrine/orm
[Master coverage image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/orm/master.svg?style=flat-square
[Master coverage]: https://scrutinizer-ci.com/g/doctrine/orm/?branch=master
[2.5 image]: https://img.shields.io/travis/doctrine/orm/2.5.svg?style=flat-square
[2.5]: https://github.com/doctrine/orm/tree/2.5
[2.5 coverage image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/orm/2.5.svg?style=flat-square
[2.5 coverage]: https://scrutinizer-ci.com/g/doctrine/orm/?branch=2.5
[Master coverage image]: https://codecov.io/gh/doctrine/orm/branch/master/graph/badge.svg
[Master coverage]: https://codecov.io/gh/doctrine/orm/branch/master
[2.7 image]: https://img.shields.io/travis/doctrine/orm/2.7.svg?style=flat-square
[2.7]: https://github.com/doctrine/orm/tree/2.7
[2.7 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.7/graph/badge.svg
[2.7 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.7

View File

@@ -47,7 +47,7 @@ Whole Doctrine\ORM\Tools\Export namespace with all its members have been depreca
## Deprecated `Doctrine\ORM\Proxy\Proxy` marker interface
Proxy objects in Doctrine ORM 3.0 will no longer implement `Doctrine\ORM\Proxy\Proxy` nor
`Doctrine\Common\Persistence\Proxy`: instead, they implement
`Doctrine\Persistence\Proxy`: instead, they implement
`ProxyManager\Proxy\GhostObjectInterface`.
These related classes have been deprecated:
@@ -439,17 +439,17 @@ above you must implement these new methods.
## Metadata Drivers
Metadata drivers have been rewritten to reuse code from Doctrine\Common. Anyone who is using the
Metadata drivers have been rewritten to reuse code from `Doctrine\Persistence`. Anyone who is using the
`Doctrine\ORM\Mapping\Driver\Driver` interface should instead refer to
`Doctrine\Common\Persistence\Mapping\Driver\MappingDriver`. Same applies to
`Doctrine\Persistence\Mapping\Driver\MappingDriver`. Same applies to
`Doctrine\ORM\Mapping\Driver\AbstractFileDriver`: you should now refer to
`Doctrine\Common\Persistence\Mapping\Driver\FileDriver`.
`Doctrine\Persistence\Mapping\Driver\FileDriver`.
Also, following mapping drivers have been deprecated, please use their replacements in Doctrine\Common as listed:
* `Doctrine\ORM\Mapping\Driver\DriverChain` => `Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain`
* `Doctrine\ORM\Mapping\Driver\PHPDriver` => `Doctrine\Common\Persistence\Mapping\Driver\PHPDriver`
* `Doctrine\ORM\Mapping\Driver\StaticPHPDriver` => `Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver`
* `Doctrine\ORM\Mapping\Driver\DriverChain` => `Doctrine\Persistence\Mapping\Driver\MappingDriverChain`
* `Doctrine\ORM\Mapping\Driver\PHPDriver` => `Doctrine\Persistence\Mapping\Driver\PHPDriver`
* `Doctrine\ORM\Mapping\Driver\StaticPHPDriver` => `Doctrine\Persistence\Mapping\Driver\StaticPHPDriver`
# Upgrade to 2.2
@@ -538,7 +538,7 @@ Previously EntityManager#find(null) returned null. It now throws an exception.
## Interface for EntityRepository
The EntityRepository now has an interface Doctrine\Common\Persistence\ObjectRepository. This means that your classes that override EntityRepository and extend find(), findOneBy() or findBy() must be adjusted to follow this interface.
The EntityRepository now has an interface Doctrine\Persistence\ObjectRepository. This means that your classes that override EntityRepository and extend find(), findOneBy() or findBy() must be adjusted to follow this interface.
## AnnotationReader changes

View File

@@ -1,9 +1,9 @@
@echo off
if "%PHPBIN%" == "" set PHPBIN=@php_bin@
if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
GOTO RUN
:USE_PEAR_PATH
set PHPBIN=%PHP_PEAR_PHP_BIN%
:RUN
"%PHPBIN%" "@bin_dir@\doctrine" %*
@echo off
if "%PHPBIN%" == "" set PHPBIN=@php_bin@
if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
GOTO RUN
:USE_PEAR_PATH
set PHPBIN=%PHP_PEAR_PHP_BIN%
:RUN
"%PHPBIN%" "@bin_dir@\doctrine" %*

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
failOnWarning="true"
>
<php>
<var name="db_driver" value="mysqli"/>
<var name="db_host" value="127.0.0.1" />
<var name="db_port" value="3306"/>
<var name="db_user" value="root" />
<var name="db_dbname" value="doctrine_tests" />
<!-- necessary change for some CLI/console output test assertions -->
<env name="COLUMNS" value="120"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../../../tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">../../../lib/Doctrine</directory>
</whitelist>
</filter>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
failOnWarning="true"
>
<php>
<var name="db_driver" value="pdo_mysql"/>
<var name="db_host" value="127.0.0.1" />
<var name="db_port" value="3306"/>
<var name="db_user" value="root" />
<var name="db_dbname" value="doctrine_tests" />
<!-- necessary change for some CLI/console output test assertions -->
<env name="COLUMNS" value="120"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../../../tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">../../../lib/Doctrine</directory>
</whitelist>
</filter>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
failOnWarning="true"
>
<php>
<var name="db_driver" value="pdo_pgsql"/>
<var name="db_host" value="localhost" />
<var name="db_user" value="postgres" />
<var name="db_password" value="postgres" />
<var name="db_dbname" value="doctrine_tests" />
<!-- necessary change for some CLI/console output test assertions -->
<env name="COLUMNS" value="120"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../../../tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">../../../lib/Doctrine</directory>
</whitelist>
</filter>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
failOnWarning="true"
>
<php>
<!-- necessary change for some CLI/console output test assertions -->
<env name="COLUMNS" value="120"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../../../tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">../../../lib/Doctrine</directory>
</whitelist>
</filter>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>

View File

@@ -18,21 +18,25 @@
"require": {
"php": "^7.1",
"ext-pdo": "*",
"doctrine/annotations": "^1.8",
"composer/package-versions-deprecated": "^1.8",
"doctrine/annotations": "^1.11.1",
"doctrine/cache": "^1.9.1",
"doctrine/collections": "^1.5",
"doctrine/common": "^2.11",
"doctrine/common": "^2.11 || ^3.0",
"doctrine/dbal": "^2.9.3",
"doctrine/event-manager": "^1.1",
"doctrine/inflector": "^1.0",
"doctrine/instantiator": "^1.3",
"doctrine/persistence": "^1.2",
"ocramius/package-versions": "^1.2",
"doctrine/lexer": "^1.0",
"doctrine/persistence": "^1.3.3 || ^2.0",
"symfony/console": "^3.0|^4.0|^5.0"
},
"require-dev": {
"doctrine/coding-standard": "^5.0",
"phpunit/phpunit": "^7.5",
"symfony/yaml": "^3.4|^4.0|^5.0"
"doctrine/coding-standard": "^6.0",
"phpstan/phpstan": "^0.12.18",
"phpunit/phpunit": "^8.0",
"symfony/yaml": "^3.4|^4.0|^5.0",
"vimeo/psalm": "^3.11"
},
"suggest": {
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"

2793
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,4 +7,4 @@ rm build -Rf
sphinx-build en build
sphinx-build -b latex en build/pdf
rubber --into build/pdf --pdf build/pdf/Doctrine2ORM.tex
rubber --into build/pdf --pdf build/pdf/Doctrine2ORM.tex

View File

@@ -1,2 +1,2 @@
#!/bin/bash
sudo apt-get update && sudo apt-get install -y python2.7 python-sphinx python-pygments
sudo apt-get update && sudo apt-get install -y python2.7 python-sphinx python-pygments

View File

@@ -22,7 +22,7 @@ into the account can either be of positive or negative money
values. Each account has a credit limit and the account is never
allowed to have a balance below that value.
For simplicity we live in a world were money is composed of
For simplicity we live in a world where money is composed of
integers only. Also we omit the receiver/sender name, stated reason
for transfer and the execution date. These all would have to be
added on the ``Entry`` object.
@@ -32,30 +32,39 @@ Our entities look like:
.. code-block:: php
<?php
namespace Bank\Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* @Entity
* @ORM\Entity
*/
class Account
{
/** @Id @GeneratedValue @Column(type="integer") */
private $id;
/** @Column(type="string", unique=true) */
private $no;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id;
/**
* @OneToMany(targetEntity="Entry", mappedBy="account", cascade={"persist"})
* @ORM\Column(type="string", unique=true)
*/
private $entries;
private string $no;
/**
* @Column(type="integer")
* @ORM\OneToMany(targetEntity="Entry", mappedBy="account", cascade={"persist"})
*/
private $maxCredit = 0;
private array $entries;
public function __construct($no, $maxCredit = 0)
/**
* @ORM\Column(type="integer")
*/
private int $maxCredit = 0;
public function __construct(string $no, int $maxCredit = 0)
{
$this->no = $no;
$this->maxCredit = $maxCredit;
@@ -64,31 +73,35 @@ Our entities look like:
}
/**
* @Entity
* @ORM\Entity
*/
class Entry
{
/** @Id @GeneratedValue @Column(type="integer") */
private $id;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id;
/**
* @ManyToOne(targetEntity="Account", inversedBy="entries")
* @ORM\ManyToOne(targetEntity="Account", inversedBy="entries")
*/
private $account;
private Account $account;
/**
* @Column(type="integer")
* @ORM\Column(type="integer")
*/
private $amount;
private int $amount;
public function __construct($account, $amount)
public function __construct(Account $account, int $amount)
{
$this->account = $account;
$this->amount = $amount;
// more stuff here, from/to whom, stated reason, execution date and such
}
public function getAmount()
public function getAmount(): Amount
{
return $this->amount;
}
@@ -146,12 +159,14 @@ collection, which means we can compute this value at runtime:
class Account
{
// .. previous code
public function getBalance()
public function getBalance(): int
{
$balance = 0;
foreach ($this->entries as $entry) {
$balance += $entry->getAmount();
}
return $balance;
}
}
@@ -175,13 +190,12 @@ relation with this method:
<?php
class Account
{
public function addEntry($amount)
public function addEntry(int $amount): void
{
$this->assertAcceptEntryAllowed($amount);
$e = new Entry($this, $amount);
$this->entries[] = $e;
return $e;
}
}
@@ -190,7 +204,10 @@ Now look at the following test-code for our entities:
.. code-block:: php
<?php
class AccountTest extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
class AccountTest extends TestCase
{
public function testAddEntry()
{
@@ -208,7 +225,7 @@ Now look at the following test-code for our entities:
{
$account = new Account("123456", $maxCredit = 200);
$this->setExpectedException("Exception");
$this->expectException(Exception::class);
$account->addEntry(-1000);
}
}
@@ -219,9 +236,12 @@ To enforce our rule we can now implement the assertion in
.. code-block:: php
<?php
class Account
{
private function assertAcceptEntryAllowed($amount)
// .. previous code
private function assertAcceptEntryAllowed(int $amount): void
{
$futureBalance = $this->getBalance() + $amount;
$allowedMinimalBalance = ($this->maxCredit * -1);
@@ -266,23 +286,22 @@ entries collection) we want to add an aggregate field called
class Account
{
/**
* @Column(type="integer")
* @ORM\Column(type="integer")
*/
private $balance = 0;
private int $balance = 0;
public function getBalance()
public function getBalance(): int
{
return $this->balance;
}
public function addEntry($amount)
public function addEntry(int $amount): void
{
$this->assertAcceptEntryAllowed($amount);
$e = new Entry($this, $amount);
$this->entries[] = $e;
$this->balance += $amount;
return $e;
}
}
@@ -306,12 +325,15 @@ potentially lead to inconsistent state. See this example:
.. code-block:: php
<?php
use Bank\Entities\Account;
// The Account $accId has a balance of 0 and a max credit limit of 200:
// request 1 account
$account1 = $em->find('Bank\Entities\Account', $accId);
$account1 = $em->find(Account::class, $accId);
// request 2 account
$account2 = $em->find('Bank\Entities\Account', $accId);
$account2 = $em->find(Account::class, $accId);
$account1->addEntry(-200);
$account2->addEntry(-200);
@@ -332,10 +354,14 @@ Optimistic locking is as easy as adding a version column:
.. code-block:: php
<?php
class Account
{
/** @Column(type="integer") @Version */
private $version;
/**
* @ORM\Column(type="integer")
* @ORM\Version
*/
private int $version;
}
The previous example would then throw an exception in the face of
@@ -349,9 +375,11 @@ the database using a FOR UPDATE.
.. code-block:: php
<?php
use Bank\Entities\Account;
use Doctrine\DBAL\LockMode;
$account = $em->find('Bank\Entities\Account', $accId, LockMode::PESSIMISTIC_READ);
$account = $em->find(Account::class, $accId, LockMode::PESSIMISTIC_READ);
Keeping Updates and Deletes in Sync
-----------------------------------
@@ -372,5 +400,3 @@ field that offers serious performance benefits over iterating all
the related objects that make up an aggregate value. Finally I
showed how you can ensure that your aggregate fields do not get out
of sync due to race-conditions and concurrent access.

View File

@@ -167,7 +167,7 @@ can be set via ``Query::setHint($name, $value)`` as shown in the
previous example with the ``HINT_CUSTOM_TREE_WALKERS`` query hint.
We will implement a custom Output Walker that allows to specify the
SQL\_NO\_CACHE query hint.
``SQL_NO_CACHE`` query hint.
.. code-block:: php
@@ -180,7 +180,7 @@ SQL\_NO\_CACHE query hint.
Our ``MysqlWalker`` will extend the default ``SqlWalker``. We will
modify the generation of the SELECT clause, adding the
SQL\_NO\_CACHE on those queries that need it:
``SQL_NO_CACHE`` on those queries that need it:
.. code-block:: php

View File

@@ -22,8 +22,8 @@ implement the ``NotifyPropertyChanged`` interface from the
.. code-block:: php
<?php
use Doctrine\Common\NotifyPropertyChanged;
use Doctrine\Common\PropertyChangedListener;
use Doctrine\Persistence\NotifyPropertyChanged;
use Doctrine\Persistence\PropertyChangedListener;
abstract class DomainObject implements NotifyPropertyChanged
{

View File

@@ -1,113 +1,113 @@
@ECHO OFF
REM Command file for Sphinx documentation
set SPHINXBUILD=sphinx-build
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Doctrine2ORM.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Doctrine2ORM.ghc
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end
@ECHO OFF
REM Command file for Sphinx documentation
set SPHINXBUILD=sphinx-build
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Doctrine2ORM.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Doctrine2ORM.ghc
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

View File

@@ -619,22 +619,17 @@ Examples:
This annotation is used in the context of relations in
:ref:`@ManyToOne <annref_manytoone>`, :ref:`@OneToOne <annref_onetoone>` fields
and in the Context of :ref:`@JoinTable <annref_jointable>` nested inside
a @ManyToMany. This annotation is not required. If it is not
specified the attributes *name* and *referencedColumnName* are
inferred from the table and primary key names.
Required attributes:
a @ManyToMany. If this annotation or both *name* and *referencedColumnName*
are missing they will be computed considering the field's name and the current
:doc:`naming strategy <namingstrategy>`.
Optional attributes:
- **name**: Column name that holds the foreign key identifier for
this relation. In the context of @JoinTable it specifies the column
name in the join table.
- **referencedColumnName**: Name of the primary key identifier that
is used for joining of this relation.
Optional attributes:
is used for joining of this relation. Defaults to *id*.
- **unique**: Determines whether this relation is exclusive between the
affected entities and should be enforced as such on the database
constraint level. Defaults to false.

View File

@@ -18,9 +18,9 @@ This chapter is split into three different sections.
One tip for working with relations is to read the relation from left to right, where the left word refers to the current Entity. For example:
- OneToMany - One instance of the current Entity has Many instances (references) to the refered Entity.
- ManyToOne - Many instances of the current Entity refer to One instance of the refered Entity.
- OneToOne - One instance of the current Entity refers to One instance of the refered Entity.
- OneToMany - One instance of the current Entity has Many instances (references) to the referred Entity.
- ManyToOne - Many instances of the current Entity refer to One instance of the referred Entity.
- OneToOne - One instance of the current Entity refers to One instance of the referred Entity.
See below for all the possible relations.

View File

@@ -1,8 +1,8 @@
Caching
=======
Doctrine provides cache drivers in the ``Common`` package for some
of the most popular caching implementations such as APC, Memcache
Doctrine provides cache drivers in the ``doctrine/cache`` package for some
of the most popular caching implementations such as APCu, Memcache
and Xcache. We also provide an ``ArrayCache`` driver which stores
the data in a PHP array. Obviously, when using ``ArrayCache``, the
cache does not persist between requests, but this is useful for
@@ -306,7 +306,7 @@ the result cache.
<?php
$query = $em->createQuery('select u from \Entities\User u');
$query->useResultCache(true);
$query->enableResultCache();
You can also configure an individual query to use a different
result cache driver.
@@ -317,19 +317,18 @@ result cache driver.
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
'/path/to/writable/directory'
);
$config = new \Doctrine\ORM\Configuration();
$query->setResultCacheDriver($cacheDriver);
.. note::
Setting the result cache driver on the query will
automatically enable the result cache for the query. If you want to
disable it pass false to ``useResultCache()``.
disable it use ``disableResultCache()``.
::
<?php
$query->useResultCache(false);
$query->disableResultCache();
If you want to set the time the cache has to live you can use the
@@ -350,12 +349,12 @@ yourself with the ``setResultCacheId()`` method.
$query->setResultCacheId('my_custom_id');
You can also set the lifetime and cache ID by passing the values as
the second and third argument to ``useResultCache()``.
the first and second argument to ``enableResultCache()``.
.. code-block:: php
<?php
$query->useResultCache(true, 3600, 'my_custom_id');
$query->enableResultCache(3600, 'my_custom_id');
Metadata Cache
~~~~~~~~~~~~~~

View File

@@ -71,8 +71,8 @@ follows:
.. code-block:: php
<?php
use Doctrine\Common\NotifyPropertyChanged,
Doctrine\Common\PropertyChangedListener;
use Doctrine\Persistence\NotifyPropertyChanged,
Doctrine\Persistence\PropertyChangedListener;
/**
* @Entity

View File

@@ -491,7 +491,7 @@ Joins between entities without associations were not possible until version
.. code-block:: php
<?php
$query = $em->createQuery('SELECT u FROM User u JOIN Blacklist b WITH u.email = b.email');
$query = $em->createQuery('SELECT u FROM User u JOIN Banlist b WITH u.email = b.email');
.. note::
The differences between WHERE, WITH and HAVING clauses may be

View File

@@ -145,49 +145,53 @@ An example for a correct notation can be found in the example
Lifecycle Events
----------------
The EntityManager and UnitOfWork trigger a bunch of events during
the life-time of their registered entities.
The ``EntityManager`` and ``UnitOfWork`` classes trigger a bunch of
events during the life-time of their registered entities.
- preRemove - The preRemove event occurs for a given entity before
the respective EntityManager remove operation for that entity is
executed. It is not called for a DQL DELETE statement.
- postRemove - The postRemove event occurs for an entity after the
- ``preRemove`` - The ``preRemove`` event occurs for a given entity
before the respective ``EntityManager`` remove operation for that
entity is executed. It is not called for a DQL ``DELETE`` statement.
- ``postRemove`` - The ``postRemove`` event occurs for an entity after the
entity has been deleted. It will be invoked after the database
delete operations. It is not called for a DQL DELETE statement.
- prePersist - The prePersist event occurs for a given entity
before the respective EntityManager persist operation for that
delete operations. It is not called for a DQL ``DELETE`` statement.
- ``prePersist`` - The ``prePersist`` event occurs for a given entity
before the respective ``EntityManager`` persist operation for that
entity is executed. It should be noted that this event is only triggered on
*initial* persist of an entity (i.e. it does not trigger on future updates).
- postPersist - The postPersist event occurs for an entity after
- ``postPersist`` - The ``postPersist`` event occurs for an entity after
the entity has been made persistent. It will be invoked after the
database insert operations. Generated primary key values are
available in the postPersist event.
- preUpdate - The preUpdate event occurs before the database
update operations to entity data. It is not called for a DQL UPDATE statement
nor when the computed changeset is empty.
- postUpdate - The postUpdate event occurs after the database
update operations to entity data. It is not called for a DQL UPDATE statement.
- postLoad - The postLoad event occurs for an entity after the
entity has been loaded into the current EntityManager from the
- ``preUpdate`` - The ``preUpdate`` event occurs before the database
update operations to entity data. It is not called for a DQL
``UPDATE`` statement nor when the computed changeset is empty.
- ``postUpdate`` - The ``postUpdate`` event occurs after the database
update operations to entity data. It is not called for a DQL
``UPDATE`` statement.
- ``postLoad`` - The postLoad event occurs for an entity after the
entity has been loaded into the current ``EntityManager`` from the
database or after the refresh operation has been applied to it.
- loadClassMetadata - The loadClassMetadata event occurs after the
- ``loadClassMetadata`` - The ``loadClassMetadata`` event occurs after the
mapping metadata for a class has been loaded from a mapping source
(annotations/xml/yaml). This event is not a lifecycle callback.
- onClassMetadataNotFound - Loading class metadata for a particular
- ``onClassMetadataNotFound`` - Loading class metadata for a particular
requested class name failed. Manipulating the given event args instance
allows providing fallback metadata even when no actual metadata exists
or could be found. This event is not a lifecycle callback.
- preFlush - The preFlush event occurs at the very beginning of a flush
operation.
- onFlush - The onFlush event occurs after the change-sets of all
- ``preFlush`` - The ``preFlush`` event occurs at the very beginning of
a flush operation.
- ``onFlush`` - The ``onFlush`` event occurs after the change-sets of all
managed entities are computed. This event is not a lifecycle
callback.
- postFlush - The postFlush event occurs at the end of a flush operation. This
- ``postFlush`` - The ``postFlush`` event occurs at the end of a flush operation. This
event is not a lifecycle callback.
- onClear - The onClear event occurs when the EntityManager#clear() operation is
invoked, after all references to entities have been removed from the unit of
work. This event is not a lifecycle callback.
- ``onClear`` - The ``onClear`` event occurs when the
``EntityManager#clear()`` operation is invoked, after all references
to entities have been removed from the unit of work. This event is not
a lifecycle callback.
.. warning::
@@ -199,7 +203,7 @@ the life-time of their registered entities.
.. warning::
Note that the postRemove event or any events triggered after an entity removal
Note that the ``postRemove`` event or any events triggered after an entity removal
can receive an uninitializable proxy in case you have configured an entity to
cascade remove relations. In this case, you should load yourself the proxy in
the associated pre event.
@@ -222,13 +226,13 @@ listeners:
- Lifecycle Event Listeners and Subscribers are classes with specific callback
methods that receives some kind of ``EventArgs`` instance.
The EventArgs instance received by the listener gives access to the entity,
EntityManager and other relevant data.
The ``EventArgs`` instance received by the listener gives access to the entity,
``EntityManager`` instance and other relevant data.
.. note::
All Lifecycle events that happen during the ``flush()`` of
an EntityManager have very specific constraints on the allowed
an ``EntityManager`` have very specific constraints on the allowed
operations that can be executed. Please read the
:ref:`reference-events-implementing-listeners` section very carefully
to understand which operations are allowed in which lifecycle event.
@@ -410,9 +414,9 @@ sit at a level above the entities and allow you to implement re-usable
behaviors across different entity classes.
Note that they require much more detailed knowledge about the inner
workings of the EntityManager and UnitOfWork. Please read the
:ref:`reference-events-implementing-listeners` section carefully if you
are trying to write your own listener.
workings of the ``EntityManager`` and ``UnitOfWork`` classes. Please
read the :ref:`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
lifecycle events in their ``getSubscribedEvents`` method and provide
@@ -423,7 +427,7 @@ A lifecycle event listener looks like the following:
.. code-block:: php
<?php
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\Persistence\Event\LifecycleEventArgs;
class MyEventListener
{
@@ -445,8 +449,8 @@ A lifecycle event subscriber may look like this:
<?php
use Doctrine\ORM\Events;
use Doctrine\Common\EventSubscriber;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\EventSubscriber;
use Doctrine\Persistence\Event\LifecycleEventArgs;
class MyEventSubscriber implements EventSubscriber
{
@@ -501,16 +505,16 @@ Implementing Event Listeners
----------------------------
This section explains what is and what is not allowed during
specific lifecycle events of the UnitOfWork. Although you get
passed the EntityManager in all of these events, you have to follow
these restrictions very carefully since operations in the wrong
event may produce lots of different errors, such as inconsistent
specific lifecycle events of the ``UnitOfWork`` class. Although you get
passed the ``EntityManager`` instance in all of these events, you have
to follow these restrictions very carefully since operations in the
wrong event may produce lots of different errors, such as inconsistent
data and lost updates/persists/removes.
For the described events that are also lifecycle callback events
the restrictions apply as well, with the additional restriction
that (prior to version 2.4) you do not have access to the
EntityManager or UnitOfWork APIs inside these events.
``EntityManager`` or ``UnitOfWork`` APIs inside these events.
prePersist
~~~~~~~~~~
@@ -586,8 +590,8 @@ entities and their associations have been computed. This means, the
- Collections scheduled for update
- Collections scheduled for removal
To make use of the onFlush event you have to be familiar with the
internal UnitOfWork API, which grants you access to the previously
To make use of the ``onFlush`` event you have to be familiar with the
internal ``UnitOfWork`` API, which grants you access to the previously
mentioned sets. See this example:
.. code-block:: php
@@ -735,7 +739,7 @@ Restrictions for this event:
the event to modify primitive field values, e.g. use
``$eventArgs->setNewValue($field, $value);`` as in the Alice to Bob example above.
- Any calls to ``EntityManager#persist()`` or
``EntityManager#remove()``, even in combination with the UnitOfWork
``EntityManager#remove()``, even in combination with the ``UnitOfWork``
API are strongly discouraged and don't work as expected outside the
flush operation.
@@ -991,4 +995,3 @@ process and manipulate the instance.
}
}

View File

@@ -20,12 +20,17 @@ Metadata and Query caches
As already mentioned earlier in the chapter about configuring
Doctrine, it is strongly discouraged to use Doctrine without a
Metadata and Query cache (preferably with APC or Memcache as the
cache driver). Operating Doctrine without these caches means
Metadata and Query cache.
Operating Doctrine without these caches means
Doctrine will need to load your mapping information on every single
request and has to parse each DQL query on every single request.
This is a waste of resources.
The preferred cache driver for metadata and query caches is ``PhpFileCache``.
This driver serializes cache items and writes them to a file.
This allows for opcode caching to be used and provides high performance in most scenarios.
See :ref:`integrating-with-the-orm`
Alternative Query Result Formats

View File

@@ -289,9 +289,15 @@ column and cascading on delete.
Overrides
---------
Used to override a mapping for an entity field or relationship.
May be applied to an entity that extends a mapped superclass
to override a relationship or field mapping defined by the mapped superclass.
Used to override a mapping for an entity field or relationship. Can only be
applied to an entity that extends a mapped superclass or uses a trait to
override a relationship or field mapping defined by the mapped superclass or
trait.
It is not possible to override attributes or associations in entity to entity
inheritance scenarios, because this can cause unforseen edge case behavior and
increases complexity in ORM internal classes.
Association Override
@@ -584,7 +590,7 @@ Things to note:
- The "attribute override" specifies the overrides base on the property name.
- The column type *CANNOT* be changed. If the column type is not equal you get a ``MappingException``
- The override can redefine all the columns except the type.
- The override can redefine all the attributes except the type.
Query the Type
--------------

View File

@@ -255,6 +255,21 @@ and for managed entities. If you want to set a type explicitly you can call
the third argument to ``setParameter()`` explicitly. It accepts either a PDO
type or a DBAL Type name for conversion.
.. note::
Even though passing DateTime instance is allowed, it impacts performance
as by default there is an attempt to load metadata for object, and if it's not found,
type is inferred from the original value.
.. code-block:: php
<?php
use Doctrine\DBAL\Types\Types;
// prevents attempt to load metadata for date time class, improving performance
$qb->setParameter('date', new \DateTimeImmutable(), Types::DATE_IMMUTABLE)
If you've got several parameters to bind to your query, you can
also use setParameters() instead of setParameter() with the
following syntax:
@@ -581,4 +596,3 @@ same query of example 6 written using
->add('from', new Expr\From('User', 'u'))
->add('where', new Expr\Comparison('u.id', '=', '?1'))
->add('orderBy', new Expr\OrderBy('u.name', 'ASC'));

View File

@@ -77,11 +77,10 @@ A query region might be something like :
Cache Regions
-------------
``Doctrine\ORM\Cache\Region\DefaultRegion`` It's the default implementation.
``Doctrine\ORM\Cache\Region\DefaultRegion`` is the default implementation.
A simplest cache region compatible with all doctrine-cache drivers but does not support locking.
``Doctrine\ORM\Cache\Region`` and ``Doctrine\ORM\Cache\ConcurrentRegion``
Defines contracts that should be implemented by a cache provider.
define contracts that should be implemented by a cache provider.
It allows you to provide your own cache implementation that might take advantage of specific cache driver.
@@ -91,11 +90,8 @@ If you want to support locking for ``READ_WRITE`` strategies you should implemen
Cache region
~~~~~~~~~~~~
Defines a contract for accessing a particular region.
``Doctrine\ORM\Cache\Region``
Defines a contract for accessing a particular cache region.
``Doctrine\ORM\Cache\Region`` defines a contract for accessing a particular
cache region.
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/Region.html>`_.
@@ -107,9 +103,7 @@ By default, Doctrine provides a very simple implementation based on file locks `
If you want to use an ``READ_WRITE`` cache, you should consider providing your own cache region.
``Doctrine\ORM\Cache\ConcurrentRegion``
Defines contract for concurrently managed data region.
``Doctrine\ORM\Cache\ConcurrentRegion`` defines a contract for concurrently managed data region.
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/ConcurrentRegion.html>`_.
@@ -177,7 +171,7 @@ Doctrine allows you to specify configurations and some points of extension for t
Enable Second Level Cache
~~~~~~~~~~~~~~~~~~~~~~~~~
To enable the second-level-cache, you should provide a cache factory
To enable the second-level-cache, you should provide a cache factory.
``\Doctrine\ORM\Cache\DefaultCacheFactory`` is the default implementation.
.. code-block:: php
@@ -203,11 +197,16 @@ Cache Factory is the main point of extension.
It allows you to provide a specific implementation of the following components :
* ``QueryCache`` Store and retrieve query cache results.
* ``CachedEntityPersister`` Store and retrieve entity results.
* ``CachedCollectionPersister`` Store and retrieve query results.
* ``EntityHydrator`` Transform an entity into a cache entry and cache entry into entities
* ``CollectionHydrator`` Transform a collection into a cache entry and cache entry into collection
``QueryCache``
stores and retrieves query cache results.
``CachedEntityPersister``
stores and retrieves entity results.
``CachedCollectionPersister``
stores and retrieves query results.
``EntityHydrator``
transforms entities into a cache entries and cache entries into entities
``CollectionHydrator``
transforms collections into cache entries and cache entries into collections
`See API Doc <http://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/DefaultCacheFactory.html>`_.
@@ -225,8 +224,8 @@ To specify a default lifetime for all regions or specify a different lifetime fo
$regionConfig = $cacheConfig->getRegionsConfiguration();
// Cache Region lifetime
$regionConfig->setLifetime('my_entity_region', 3600); // Time to live for a specific region; In seconds
$regionConfig->setDefaultLifetime(7200); // Default time to live; In seconds
$regionConfig->setLifetime('my_entity_region', 3600); // Time to live for a specific region (in seconds)
$regionConfig->setDefaultLifetime(7200); // Default time to live (in seconds)
Cache Log
@@ -267,8 +266,9 @@ By providing a cache logger you should be able to get information about all cach
// Get the total number of cached entries *not* found in all regions.
$logger->getMissCount();
If you want to get more information you should implement ``\Doctrine\ORM\Cache\Logging\CacheLogger``.
and collect all information you want.
If you want to get more information you should implement
``\Doctrine\ORM\Cache\Logging\CacheLogger`` and collect
all the information you want.
`See API Doc <http://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/Logging/CacheLogger.html>`_.
@@ -277,8 +277,11 @@ Entity cache definition
-----------------------
* Entity cache configuration allows you to define the caching strategy and region for an entity.
* ``usage`` Specifies the caching strategy: ``READ_ONLY``, ``NONSTRICT_READ_WRITE``, ``READ_WRITE``. see :ref:`reference-second-level-cache-mode`
* ``region`` Optional value that specifies the name of the second level cache region.
* ``usage`` specifies the caching strategy: ``READ_ONLY``,
``NONSTRICT_READ_WRITE``, ``READ_WRITE``.
See :ref:`reference-second-level-cache-mode`.
* ``region`` is an optional value that specifies the name of the second
level cache region.
.. configuration-block::
@@ -579,7 +582,8 @@ The Cache Mode controls how a particular query interacts with the second-level c
DELETE / UPDATE queries
~~~~~~~~~~~~~~~~~~~~~~~
DQL UPDATE / DELETE statements are ported directly into a database and bypass the second-level cache,
DQL UPDATE / DELETE statements are ported directly into a database and bypass
the second-level cache.
Entities that are already cached will NOT be invalidated.
However the cached data could be evicted using the cache API or an special query hint.
@@ -622,7 +626,7 @@ Using the repository query cache
--------------------------------
As well as ``Query Cache`` all persister queries store only identifier values for an individual query.
All persister use a single timestamps cache region keeps track of the last update for each persister,
All persisters use a single timestamp cache region to keep track of the last update for each persister,
When a query is loaded from cache, the timestamp region is checked for the last update for that persister.
Using the last update timestamps as part of the query key invalidate the cache key when an update occurs.
@@ -641,7 +645,7 @@ Using the last update timestamps as part of the query key invalidate the cache k
$em->clear();
// Reload from database.
// At this point the query cache key if not logger valid, the select goes straight
// At this point the query cache key is no longer valid, the select goes straight to the database
$entities = $em->getRepository('Entity\Country')->findAll();
Cache API
@@ -728,4 +732,5 @@ Paginator
~~~~~~~~~
Count queries generated by ``Doctrine\ORM\Tools\Pagination\Paginator`` are not cached by second-level cache.
Although entities and query result are cached count queries will hit the database every time.
Although entities and query result are cached, count queries will hit the
database every time.

View File

@@ -250,6 +250,12 @@ as follows:
- If X is a detached entity, an exception will be thrown on
flush.
.. caution::
Do not pass detached entities to the persist operation. The persist operation always
considers entities that are not yet known to the ``EntityManager`` as new entities
(refer to the ``STATE_NEW`` constant inside the ``UnitOfWork``).
Removing entities
-----------------
@@ -315,7 +321,7 @@ in multiple ways with very different performance impacts.
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine 2
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()\`.
``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
@@ -330,6 +336,13 @@ in multiple ways with very different performance impacts.
because Doctrine will fetch and remove all associated entities
explicitly nevertheless.
.. note::
Calling ``remove`` on an entity will remove the object from the identiy
map and therefore detach it. Querying the same entity again, for example
via a lazy loaded relation, will return a new object.
Detaching entities
------------------

View File

@@ -8,9 +8,7 @@ or address are the primary use case for this feature.
.. note::
Embeddables can not contain references to entities. They can however compose
other embeddables in addition to holding properties with basic ``@Column``
mapping.
Embeddables can only contain properties with basic ``@Column`` mapping.
For the purposes of this tutorial, we will assume that you have a ``User``
class in your application and you would like to store an address in

View File

@@ -3,7 +3,7 @@ Extra Lazy Associations
.. versionadded:: 2.1
In many cases associations between entities can get pretty large. Even in a simple scenario like a blog.
In many cases associations between entities can get pretty large. Even in a simple scenario like a blog
where posts can be commented, you always have to assume that a post draws hundreds of comments.
In Doctrine 2.0 if you accessed an association it would always get loaded completely into memory. This
can lead to pretty serious performance problems, if your associations contain several hundreds or thousands

View File

@@ -488,7 +488,6 @@ classes. We'll store them in ``src/Bug.php`` and ``src/User.php``, respectively.
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="BugRepository")
* @ORM\Table(name="bugs")
*/
class Bug

View File

@@ -291,6 +291,5 @@ Outlook into the Future
~~~~~~~~~~~~~~~~~~~~~~~
For the inverse side of a many-to-many associations there will be a way to persist the keys and the order
as a third and fourth parameter into the join table. This feature is discussed in `DDC-213 <http://www.doctrine-project.org/jira/browse/DDC-213>`_
as a third and fourth parameter into the join table. This feature is discussed in `#2817 <https://github.com/doctrine/orm/issues/2817>`_
This feature cannot be implemented for one-to-many associations, because they are never the owning side.

View File

@@ -19,15 +19,14 @@
namespace Doctrine\ORM;
use Doctrine\Common\Persistence\Mapping\MappingException;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Cache\QueryCacheKey;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\Persistence\Mapping\MappingException;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
@@ -73,6 +72,7 @@ abstract class AbstractQuery
* The parameter map of this query.
*
* @var ArrayCollection|Parameter[]
* @psalm-var ArrayCollection<int, Parameter>
*/
protected $parameters;
@@ -241,7 +241,7 @@ abstract class AbstractQuery
*
* @param integer $lifetime
*
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return static This query instance.
*/
public function setLifetime($lifetime)
{
@@ -261,7 +261,7 @@ abstract class AbstractQuery
/**
* @param integer $cacheMode
*
* @return \Doctrine\ORM\AbstractQuery This query instance.
* @return static This query instance.
*/
public function setCacheMode($cacheMode)
{
@@ -322,11 +322,13 @@ abstract class AbstractQuery
*/
public function getParameter($key)
{
$key = Query\Parameter::normalizeName($key);
$filteredParameters = $this->parameters->filter(
function (Query\Parameter $parameter) use ($key) : bool {
$parameterName = $parameter->getName();
return $key === $parameterName || (string) $key === (string) $parameterName;
return $key === $parameterName;
}
);
@@ -339,11 +341,14 @@ abstract class AbstractQuery
* @param ArrayCollection|mixed[] $parameters
*
* @return static This query instance.
*
* @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters
*/
public function setParameters($parameters)
{
// BC compatibility with 2.3-
if (is_array($parameters)) {
/** @psalm-var ArrayCollection<int, Parameter> $parameterCollection */
$parameterCollection = new ArrayCollection();
foreach ($parameters as $key => $value) {
@@ -389,9 +394,11 @@ abstract class AbstractQuery
*
* @param mixed $value
*
* @return array|string
* @return mixed[]|string|int|float|bool
*
* @throws \Doctrine\ORM\ORMInvalidArgumentException
*
* @psalm-return array|scalar
*/
public function processParameterValue($value)
{
@@ -469,7 +476,7 @@ abstract class AbstractQuery
*/
private function translateNamespaces(Query\ResultSetMapping $rsm)
{
$translate = function ($alias) {
$translate = function ($alias) : string {
return $this->_em->getClassMetadata($alias)->getName();
};
@@ -630,7 +637,7 @@ abstract class AbstractQuery
/**
* Defines how long the result cache will be active before expire.
*
* @param integer $lifetime How long the cache entry is valid.
* @param int|null $lifetime How long the cache entry is valid.
*
* @return static This query instance.
*/
@@ -965,10 +972,11 @@ abstract class AbstractQuery
$this->setParameters($parameters);
}
$setCacheEntry = function() {};
$setCacheEntry = static function () : void {
};
if ($this->_hydrationCacheProfile !== null) {
list($cacheKey, $realCacheKey) = $this->getHydrationCacheId();
[$cacheKey, $realCacheKey] = $this->getHydrationCacheId();
$queryCacheProfile = $this->getHydrationCacheProfile();
$cache = $queryCacheProfile->getResultCacheDriver();
@@ -982,7 +990,7 @@ abstract class AbstractQuery
$result = [];
}
$setCacheEntry = function($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) {
$setCacheEntry = static function ($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile) : void {
$result[$realCacheKey] = $data;
$cache->save($cacheKey, $result, $queryCacheProfile->getLifetime());
@@ -1069,7 +1077,7 @@ abstract class AbstractQuery
* Will return the configured id if it exists otherwise a hash will be
* automatically generated for you.
*
* @return array ($key, $hash)
* @return array<string, string> ($key, $hash)
*/
protected function getHydrationCacheId()
{

View File

@@ -60,9 +60,6 @@ class DefaultCache implements Cache
*/
private $defaultQueryCache;
/**
* {@inheritdoc}
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;

View File

@@ -348,7 +348,9 @@ class DefaultQueryCache implements QueryCache
* @param array $assoc
* @param mixed $assocValue
*
* @return array|null
* @return mixed[]|null
*
* @psalm-return array{targetEntity: string, type: mixed, list?: array[], identifier?: array}|null
*/
private function storeAssociationCache(QueryCacheKey $key, array $assoc, $assocValue)
{

View File

@@ -33,17 +33,17 @@ use Doctrine\ORM\Cache\QueryCacheKey;
class StatisticsCacheLogger implements CacheLogger
{
/**
* @var array
* @var int[]
*/
private $cacheMissCountMap = [];
/**
* @var array
* @var int[]
*/
private $cacheHitCountMap = [];
/**
* @var array
* @var int[]
*/
private $cachePutCountMap = [];
@@ -142,7 +142,7 @@ class StatisticsCacheLogger implements CacheLogger
*
* @param string $regionName The name of the cache region.
*
* @return integer
* @return int
*/
public function getRegionHitCount($regionName)
{
@@ -154,7 +154,7 @@ class StatisticsCacheLogger implements CacheLogger
*
* @param string $regionName The name of the cache region.
*
* @return integer
* @return int
*/
public function getRegionMissCount($regionName)
{
@@ -166,7 +166,7 @@ class StatisticsCacheLogger implements CacheLogger
*
* @param string $regionName The name of the cache region.
*
* @return integer
* @return int
*/
public function getRegionPutCount($regionName)
{
@@ -222,7 +222,7 @@ class StatisticsCacheLogger implements CacheLogger
/**
* Get the total number of put in cache.
*
* @return integer
* @return int
*/
public function getPutCount()
{
@@ -232,7 +232,7 @@ class StatisticsCacheLogger implements CacheLogger
/**
* Get the total number of entries successfully retrieved from cache.
*
* @return integer
* @return int
*/
public function getHitCount()
{
@@ -242,7 +242,7 @@ class StatisticsCacheLogger implements CacheLogger
/**
* Get the total number of cached entries *not* found in cache.
*
* @return integer
* @return int
*/
public function getMissCount()
{

View File

@@ -144,7 +144,7 @@ abstract class AbstractCollectionPersister implements CachedCollectionPersister
* @param \Doctrine\ORM\PersistentCollection $collection
* @param \Doctrine\ORM\Cache\CollectionCacheKey $key
*
* @return \Doctrine\ORM\PersistentCollection|null
* @return object[]|null
*/
public function loadCollectionCache(PersistentCollection $collection, CollectionCacheKey $key)
{

View File

@@ -283,17 +283,17 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* Generates a string of currently query
*
* @param array $query
* @param string $criteria
* @param array $orderBy
* @param integer $limit
* @param integer $offset
* @param string $query
* @param string[]|Criteria $criteria
* @param string[] $orderBy
* @param int $limit
* @param int $offset
*
* @return string
*/
protected function getHash($query, $criteria, array $orderBy = null, $limit = null, $offset = null)
{
list($params) = ($criteria instanceof Criteria)
[$params] = $criteria instanceof Criteria
? $this->persister->expandCriteriaParameters($criteria)
: $this->persister->expandParameters($criteria);
@@ -544,19 +544,18 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritdoc}
*/
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
{
$persister = $this->uow->getCollectionPersister($assoc);
$hasCache = ($persister instanceof CachedPersister);
$key = null;
if ( ! $hasCache) {
return $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $coll);
return $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection);
}
$ownerId = $this->uow->getEntityIdentifier($coll->getOwner());
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
$key = $this->buildCollectionCacheKey($assoc, $ownerId);
$list = $persister->loadCollectionCache($coll, $key);
$list = $persister->loadCollectionCache($collection, $key);
if ($list !== null) {
if ($this->cacheLogger) {
@@ -566,7 +565,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $list;
}
$list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $coll);
$list = $this->persister->loadManyToManyCollection($assoc, $sourceEntity, $collection);
$persister->storeCollectionCache($key, $list);
@@ -580,18 +579,18 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
/**
* {@inheritdoc}
*/
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
{
$persister = $this->uow->getCollectionPersister($assoc);
$hasCache = ($persister instanceof CachedPersister);
if ( ! $hasCache) {
return $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $coll);
return $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection);
}
$ownerId = $this->uow->getEntityIdentifier($coll->getOwner());
$ownerId = $this->uow->getEntityIdentifier($collection->getOwner());
$key = $this->buildCollectionCacheKey($assoc, $ownerId);
$list = $persister->loadCollectionCache($coll, $key);
$list = $persister->loadCollectionCache($collection, $key);
if ($list !== null) {
if ($this->cacheLogger) {
@@ -601,7 +600,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
return $list;
}
$list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $coll);
$list = $this->persister->loadOneToManyCollection($assoc, $sourceEntity, $collection);
$persister->storeCollectionCache($key, $list);

View File

@@ -100,6 +100,12 @@ class NonStrictReadWriteCachedEntityPersister extends AbstractEntityPersister
$this->queuedCache['update'][] = $entity;
}
/**
* @param object $entity
* @param bool $isChanged
*
* @return bool
*/
private function updateCache($entity, $isChanged)
{
$class = $this->metadataFactory->getMetadataFor(get_class($entity));

View File

@@ -249,6 +249,8 @@ class FileLockRegion implements ConcurrentRegion
/**
* {@inheritdoc}
*
* @return bool
*/
public function unlock(CacheKey $key, Lock $lock)
{

View File

@@ -25,8 +25,6 @@ use Doctrine\Common\Annotations\CachedReader;
use Doctrine\Common\Annotations\SimpleAnnotationReader;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache as CacheDriver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\Common\Proxy\AbstractProxyFactory;
use Doctrine\ORM\Cache\CacheConfiguration;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
@@ -39,6 +37,9 @@ use Doctrine\ORM\Mapping\NamingStrategy;
use Doctrine\ORM\Mapping\QuoteStrategy;
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
use Doctrine\ORM\Repository\RepositoryFactory;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Persistence\ObjectRepository;
use function interface_exists;
/**
* Configuration container for all configuration options of Doctrine.
@@ -441,6 +442,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $name
*
* @return string|null
* @psalm-return ?class-string
*/
public function getCustomStringFunction($name)
{
@@ -493,6 +495,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $name
*
* @return string|null
* @psalm-return ?class-string
*/
public function getCustomNumericFunction($name)
{
@@ -533,6 +536,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string|callable $className Class name or a callable that returns the function.
*
* @return void
*
* @psalm-param class-string|callable $className
*/
public function addCustomDatetimeFunction($name, $className)
{
@@ -545,6 +550,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $name
*
* @return string|null
*
* @psalm-return ?class-string $name
*/
public function getCustomDatetimeFunction($name)
{
@@ -566,6 +573,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param array $functions The map of custom DQL date/time functions.
*
* @return void
*
* @psalm-param array<string, string> $functions
*/
public function setCustomDatetimeFunctions(array $functions)
{
@@ -596,6 +605,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $modeName The hydration mode name.
*
* @return string|null The hydrator class name.
*
* @psalm-return ?class-string
*/
public function getCustomHydrationMode($modeName)
{
@@ -623,6 +634,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @param string $cmfName
*
* @return void
*
* @psalm-param class-string $cmfName
*/
public function setClassMetadataFactoryName($cmfName)
{
@@ -631,6 +644,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
/**
* @return string
*
* @psalm-return class-string
*/
public function getClassMetadataFactoryName()
{
@@ -657,8 +672,10 @@ class Configuration extends \Doctrine\DBAL\Configuration
*
* @param string $name The name of the filter.
*
* @return string The class name of the filter, or null if it is not
* @return string|null The class name of the filter, or null if it is not
* defined.
*
* @psalm-return ?class-string
*/
public function getFilterClassName($name)
{
@@ -676,7 +693,7 @@ class Configuration extends \Doctrine\DBAL\Configuration
*
* @return void
*
* @throws ORMException If not is a \Doctrine\Common\Persistence\ObjectRepository
* @throws ORMException If $classname is not an ObjectRepository.
*/
public function setDefaultRepositoryClassName($className)
{
@@ -695,6 +712,8 @@ class Configuration extends \Doctrine\DBAL\Configuration
* @since 2.2
*
* @return string
*
* @psalm-return class-string
*/
public function getDefaultRepositoryClassName()
{
@@ -918,3 +937,5 @@ class Configuration extends \Doctrine\DBAL\Configuration
$this->_attributes['defaultQueryHints'][$name] = $value;
}
}
interface_exists(MappingDriver::class);

View File

@@ -21,7 +21,7 @@ namespace Doctrine\ORM\Decorator;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Common\Persistence\ObjectManagerDecorator;
use Doctrine\Persistence\ObjectManagerDecorator;
/**
* Base class for EntityManager decorators
@@ -65,7 +65,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function beginTransaction()
{
return $this->wrapped->beginTransaction();
$this->wrapped->beginTransaction();
}
/**
@@ -81,7 +81,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function commit()
{
return $this->wrapped->commit();
$this->wrapped->commit();
}
/**
@@ -89,7 +89,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function rollback()
{
return $this->wrapped->rollback();
$this->wrapped->rollback();
}
/**
@@ -153,7 +153,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function close()
{
return $this->wrapped->close();
$this->wrapped->close();
}
/**
@@ -169,15 +169,15 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function lock($entity, $lockMode, $lockVersion = null)
{
return $this->wrapped->lock($entity, $lockMode, $lockVersion);
$this->wrapped->lock($entity, $lockMode, $lockVersion);
}
/**
* {@inheritdoc}
*/
public function find($entityName, $id, $lockMode = null, $lockVersion = null)
public function find($className, $id, $lockMode = null, $lockVersion = null)
{
return $this->wrapped->find($entityName, $id, $lockMode, $lockVersion);
return $this->wrapped->find($className, $id, $lockMode, $lockVersion);
}
/**
@@ -185,7 +185,7 @@ abstract class EntityManagerDecorator extends ObjectManagerDecorator implements
*/
public function flush($entity = null)
{
return $this->wrapped->flush($entity);
$this->wrapped->flush($entity);
}
/**

View File

@@ -28,7 +28,10 @@ use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Query\FilterCollection;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Persistence\Mapping\MappingException;
use Doctrine\Persistence\ObjectRepository;
use Throwable;
use function ltrim;
use const E_USER_DEPRECATED;
use function trigger_error;
@@ -325,7 +328,7 @@ use function trigger_error;
*/
public function createNamedNativeQuery($name)
{
list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
[$sql, $rsm] = $this->config->getNamedNativeQuery($name);
return $this->createNativeQuery($sql, $rsm);
}
@@ -371,7 +374,7 @@ use function trigger_error;
/**
* Finds an Entity by its identifier.
*
* @param string $entityName The class name of the entity to find.
* @param string $className The class name of the entity to find.
* @param mixed $id The identity of the entity to find.
* @param integer|null $lockMode One of the \Doctrine\DBAL\LockMode::* constants
* or NULL if no specific lock mode should be used
@@ -386,9 +389,9 @@ use function trigger_error;
* @throws TransactionRequiredException
* @throws ORMException
*/
public function find($entityName, $id, $lockMode = null, $lockVersion = null)
public function find($className, $id, $lockMode = null, $lockVersion = null)
{
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
$class = $this->metadataFactory->getMetadataFor(ltrim($className, '\\'));
if ($lockMode !== null) {
$this->checkLockRequirements($lockMode, $class);
@@ -546,9 +549,9 @@ use function trigger_error;
*
* @return void
*
* @throws ORMInvalidArgumentException if a non-null non-string value is given
* @throws \Doctrine\Common\Persistence\Mapping\MappingException if a $entityName is given, but that entity is not
* found in the mappings
* @throws ORMInvalidArgumentException If a non-null non-string value is given.
* @throws MappingException If a $entityName is given, but that entity is not
* found in the mappings.
*/
public function clear($entityName = null)
{
@@ -729,7 +732,7 @@ use function trigger_error;
*
* @param string $entityName The name of the entity.
*
* @return \Doctrine\Common\Persistence\ObjectRepository|\Doctrine\ORM\EntityRepository The repository class.
* @return ObjectRepository|EntityRepository The repository class.
*/
public function getRepository($entityName)
{

View File

@@ -19,8 +19,8 @@
namespace Doctrine\ORM;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\ObjectManager;
/**
* EntityManager interface

View File

@@ -19,11 +19,11 @@
namespace Doctrine\ORM;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\Selectable;
use Doctrine\Common\Inflector\Inflector;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\Common\Collections\Selectable;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Persistence\ObjectRepository;
/**
* An EntityRepository serves as a repository for entities with generic as well as

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
use Doctrine\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs;
/**
* Lifecycle Events are triggered by the UnitOfWork during lifecycle transitions

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClassMetadataEventArgs;
use Doctrine\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClassMetadataEventArgs;
/**
* Class that holds event arguments for a loadMetadata event.

View File

@@ -19,9 +19,10 @@
namespace Doctrine\ORM\Event;
use Doctrine\Common\Persistence\Event\ManagerEventArgs;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Persistence\Event\ManagerEventArgs;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\ObjectManager;
use function interface_exists;
/**
* Class that holds event arguments for a `onClassMetadataNotFound` event.
@@ -84,3 +85,4 @@ class OnClassMetadataNotFoundEventArgs extends ManagerEventArgs
}
}
interface_exists(ClassMetadata::class);

View File

@@ -38,7 +38,7 @@ class OnClearEventArgs extends \Doctrine\Common\EventArgs
private $em;
/**
* @var string
* @var string|null
*/
private $entityClass;

View File

@@ -40,7 +40,7 @@ abstract class AbstractIdGenerator
* By default, this method returns FALSE. Generators that have this requirement
* must override this method and return TRUE.
*
* @return boolean
* @return bool
*/
public function isPostInsertGenerator()
{

View File

@@ -228,14 +228,14 @@ abstract class AbstractHydrator
*
* Template method.
*
* @param array $data The row data.
* @param array $result The result to fill.
* @param mixed[] $row The row data.
* @param mixed[] $result The result to fill.
*
* @return void
*
* @throws HydrationException
*/
protected function hydrateRowData(array $data, array &$result)
protected function hydrateRowData(array $row, array &$result)
{
throw new HydrationException("hydrateRowData() not implemented by this hydrator.");
}
@@ -260,8 +260,19 @@ abstract class AbstractHydrator
* @param array &$id Dql-Alias => ID-Hash.
* @param array &$nonemptyComponents Does this DQL-Alias has at least one non NULL value?
*
* @return array An array with all the fields (name => value) of the data row,
* grouped by their component alias.
* @return array<string, array<string, mixed>> An array with all the fields
* (name => value) of the data
* row, grouped by their
* component alias.
*
* @psalm-return array{
* data: array<array-key, array>,
* newObjects?: array<array-key, array{
* class: mixed,
* args?: array
* }>,
* scalars?: array
* }
*/
protected function gatherRowData(array $data, array &$id, array &$nonemptyComponents)
{

View File

@@ -47,8 +47,8 @@ class ScalarHydrator extends AbstractHydrator
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $data, array &$result)
protected function hydrateRowData(array $row, array &$result)
{
$result[] = $this->gatherScalarRowData($data);
$result[] = $this->gatherScalarRowData($row);
}
}

View File

@@ -22,6 +22,7 @@ namespace Doctrine\ORM\Internal\Hydration;
use PDO;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query;
use function array_keys;
use function in_array;
class SimpleObjectHydrator extends AbstractHydrator
@@ -77,7 +78,7 @@ class SimpleObjectHydrator extends AbstractHydrator
/**
* {@inheritdoc}
*/
protected function hydrateRowData(array $sqlResult, array &$result)
protected function hydrateRowData(array $row, array &$result)
{
$entityName = $this->class->name;
$data = [];
@@ -92,27 +93,27 @@ class SimpleObjectHydrator extends AbstractHydrator
$discrColumnName = $metaMappingDiscrColumnName;
}
if ( ! isset($sqlResult[$discrColumnName])) {
if (! isset($row[$discrColumnName])) {
throw HydrationException::missingDiscriminatorColumn($entityName, $discrColumnName, key($this->_rsm->aliasMap));
}
if ($sqlResult[$discrColumnName] === '') {
if ($row[$discrColumnName] === '') {
throw HydrationException::emptyDiscriminatorValue(key($this->_rsm->aliasMap));
}
$discrMap = $this->class->discriminatorMap;
if ( ! isset($discrMap[$sqlResult[$discrColumnName]])) {
throw HydrationException::invalidDiscriminatorValue($sqlResult[$discrColumnName], array_keys($discrMap));
if (! isset($discrMap[$row[$discrColumnName]])) {
throw HydrationException::invalidDiscriminatorValue($row[$discrColumnName], array_keys($discrMap));
}
$entityName = $discrMap[$sqlResult[$discrColumnName]];
$discrColumnValue = $sqlResult[$discrColumnName];
$entityName = $discrMap[$row[$discrColumnName]];
$discrColumnValue = $row[$discrColumnName];
unset($sqlResult[$discrColumnName]);
unset($row[$discrColumnName]);
}
foreach ($sqlResult as $column => $value) {
foreach ($row as $column => $value) {
// An ObjectHydrator should be used instead of SimpleObjectHydrator
if (isset($this->_rsm->relationMap[$column])) {
throw new \Exception(sprintf('Unable to retrieve association information for column "%s"', $column));

View File

@@ -89,7 +89,7 @@ final class HydrationCompleteHandler
$this->deferredPostLoadInvocations = [];
foreach ($toInvoke as $classAndEntity) {
list($class, $invoke, $entity) = $classAndEntity;
[$class, $invoke, $entity] = $classAndEntity;
$this->listenersInvoker->invoke(
$class,

View File

@@ -58,7 +58,7 @@ class AssociationBuilder
/**
* @param string $fieldName
*
* @return AssociationBuilder
* @return static
*/
public function mappedBy($fieldName)
{
@@ -70,7 +70,7 @@ class AssociationBuilder
/**
* @param string $fieldName
*
* @return AssociationBuilder
* @return static
*/
public function inversedBy($fieldName)
{
@@ -80,7 +80,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeAll()
{
@@ -90,7 +90,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadePersist()
{
@@ -100,7 +100,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeRemove()
{
@@ -110,7 +110,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeMerge()
{
@@ -120,7 +120,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeDetach()
{
@@ -130,7 +130,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function cascadeRefresh()
{
@@ -140,7 +140,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function fetchExtraLazy()
{
@@ -150,7 +150,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function fetchEager()
{
@@ -160,7 +160,7 @@ class AssociationBuilder
}
/**
* @return AssociationBuilder
* @return static
*/
public function fetchLazy()
{
@@ -179,7 +179,7 @@ class AssociationBuilder
* @param string|null $onDelete
* @param string|null $columnDef
*
* @return AssociationBuilder
* @return static
*/
public function addJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
{
@@ -198,7 +198,7 @@ class AssociationBuilder
/**
* Sets field as primary key.
*
* @return self
* @return static
*/
public function makePrimaryKey()
{
@@ -210,7 +210,7 @@ class AssociationBuilder
/**
* Removes orphan entities when detached from their parent.
*
* @return self
* @return static
*/
public function orphanRemoval()
{

View File

@@ -57,7 +57,7 @@ class ClassMetadataBuilder
/**
* Marks the class as mapped superclass.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setMappedSuperClass()
{
@@ -70,7 +70,7 @@ class ClassMetadataBuilder
/**
* Marks the class as embeddable.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setEmbeddable()
{
@@ -107,7 +107,7 @@ class ClassMetadataBuilder
*
* @param string $repositoryClassName
*
* @return ClassMetadataBuilder
* @return static
*/
public function setCustomRepositoryClass($repositoryClassName)
{
@@ -119,7 +119,7 @@ class ClassMetadataBuilder
/**
* Marks class read only.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setReadOnly()
{
@@ -133,7 +133,7 @@ class ClassMetadataBuilder
*
* @param string $name
*
* @return ClassMetadataBuilder
* @return static
*/
public function setTable($name)
{
@@ -148,7 +148,7 @@ class ClassMetadataBuilder
* @param array $columns
* @param string $name
*
* @return ClassMetadataBuilder
* @return static
*/
public function addIndex(array $columns, $name)
{
@@ -167,7 +167,7 @@ class ClassMetadataBuilder
* @param array $columns
* @param string $name
*
* @return ClassMetadataBuilder
* @return static
*/
public function addUniqueConstraint(array $columns, $name)
{
@@ -186,7 +186,7 @@ class ClassMetadataBuilder
* @param string $name
* @param string $dqlQuery
*
* @return ClassMetadataBuilder
* @return static
*/
public function addNamedQuery($name, $dqlQuery)
{
@@ -203,7 +203,7 @@ class ClassMetadataBuilder
/**
* Sets class as root of a joined table inheritance hierarchy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setJoinedTableInheritance()
{
@@ -215,7 +215,7 @@ class ClassMetadataBuilder
/**
* Sets class as root of a single table inheritance hierarchy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setSingleTableInheritance()
{
@@ -231,7 +231,7 @@ class ClassMetadataBuilder
* @param string $type
* @param int $length
*
* @return ClassMetadataBuilder
* @return static
*/
public function setDiscriminatorColumn($name, $type = 'string', $length = 255)
{
@@ -252,7 +252,7 @@ class ClassMetadataBuilder
* @param string $name
* @param string $class
*
* @return ClassMetadataBuilder
* @return static
*/
public function addDiscriminatorMapClass($name, $class)
{
@@ -264,7 +264,7 @@ class ClassMetadataBuilder
/**
* Sets deferred explicit change tracking policy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setChangeTrackingPolicyDeferredExplicit()
{
@@ -276,7 +276,7 @@ class ClassMetadataBuilder
/**
* Sets notify change tracking policy.
*
* @return ClassMetadataBuilder
* @return static
*/
public function setChangeTrackingPolicyNotify()
{
@@ -291,7 +291,7 @@ class ClassMetadataBuilder
* @param string $methodName
* @param string $event
*
* @return ClassMetadataBuilder
* @return static
*/
public function addLifecycleEvent($methodName, $event)
{
@@ -307,7 +307,7 @@ class ClassMetadataBuilder
* @param string $type
* @param array $mapping
*
* @return ClassMetadataBuilder
* @return static
*/
public function addField($name, $type, array $mapping = [])
{

View File

@@ -74,7 +74,7 @@ class FieldBuilder
*
* @param int $length
*
* @return FieldBuilder
* @return static
*/
public function length($length)
{
@@ -88,7 +88,7 @@ class FieldBuilder
*
* @param bool $flag
*
* @return FieldBuilder
* @return static
*/
public function nullable($flag = true)
{
@@ -102,7 +102,7 @@ class FieldBuilder
*
* @param bool $flag
*
* @return FieldBuilder
* @return static
*/
public function unique($flag = true)
{
@@ -116,7 +116,7 @@ class FieldBuilder
*
* @param string $name
*
* @return FieldBuilder
* @return static
*/
public function columnName($name)
{
@@ -130,7 +130,7 @@ class FieldBuilder
*
* @param int $p
*
* @return FieldBuilder
* @return static
*/
public function precision($p)
{
@@ -144,7 +144,7 @@ class FieldBuilder
*
* @param int $s
*
* @return FieldBuilder
* @return static
*/
public function scale($s)
{
@@ -167,7 +167,7 @@ class FieldBuilder
/**
* Sets field as primary key.
*
* @return FieldBuilder
* @return static
*/
public function makePrimaryKey()
{
@@ -182,7 +182,7 @@ class FieldBuilder
* @param string $name
* @param mixed $value
*
* @return FieldBuilder
* @return static
*/
public function option($name, $value)
{
@@ -194,7 +194,7 @@ class FieldBuilder
/**
* @param string $strategy
*
* @return FieldBuilder
* @return static
*/
public function generatedValue($strategy = 'AUTO')
{
@@ -206,7 +206,7 @@ class FieldBuilder
/**
* Sets field versioned.
*
* @return FieldBuilder
* @return static
*/
public function isVersionField()
{
@@ -222,7 +222,7 @@ class FieldBuilder
* @param int $allocationSize
* @param int $initialValue
*
* @return FieldBuilder
* @return static
*/
public function setSequenceGenerator($sequenceName, $allocationSize = 1, $initialValue = 1)
{
@@ -240,7 +240,7 @@ class FieldBuilder
*
* @param string $def
*
* @return FieldBuilder
* @return static
*/
public function columnDefinition($def)
{

View File

@@ -42,7 +42,7 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
/**
* @param string $name
*
* @return ManyToManyAssociationBuilder
* @return static
*/
public function setJoinTable($name)
{
@@ -61,7 +61,7 @@ class ManyToManyAssociationBuilder extends OneToManyAssociationBuilder
* @param string|null $onDelete
* @param string|null $columnDef
*
* @return ManyToManyAssociationBuilder
* @return static
*/
public function addInverseJoinColumn($columnName, $referencedColumnName, $nullable = true, $unique = false, $onDelete = null, $columnDef = null)
{

View File

@@ -32,7 +32,7 @@ class OneToManyAssociationBuilder extends AssociationBuilder
/**
* @param array $fieldNames
*
* @return OneToManyAssociationBuilder
* @return static
*/
public function setOrderBy(array $fieldNames)
{
@@ -44,7 +44,7 @@ class OneToManyAssociationBuilder extends AssociationBuilder
/**
* @param string $fieldName
*
* @return OneToManyAssociationBuilder
* @return static
*/
public function setIndexBy($fieldName)
{

View File

@@ -19,9 +19,6 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory;
use Doctrine\Common\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
use Doctrine\Common\Persistence\Mapping\ReflectionService;
use Doctrine\DBAL\Platforms;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
@@ -30,8 +27,14 @@ use Doctrine\ORM\Events;
use Doctrine\ORM\Id\BigIntegerIdentityGenerator;
use Doctrine\ORM\Id\IdentityGenerator;
use Doctrine\ORM\ORMException;
use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory;
use Doctrine\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Persistence\Mapping\ReflectionService;
use ReflectionClass;
use ReflectionException;
use function assert;
use function interface_exists;
/**
* The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
@@ -57,7 +60,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
private $targetPlatform;
/**
* @var \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver
* @var MappingDriver
*/
private $driver;
@@ -276,6 +279,11 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
if ( ! $class->discriminatorColumn) {
throw MappingException::missingDiscriminatorColumn($class->name);
}
foreach ($class->subClasses as $subClass) {
if ((new ReflectionClass($subClass))->name !== $subClass) {
throw MappingException::invalidClassInDiscriminatorMap($subClass, $class->name);
}
}
}
} else if ($class->isMappedSuperclass && $class->name == $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
// second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
@@ -402,7 +410,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass)
{
foreach ($parentClass->fieldMappings as $mapping) {
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass && ! $parentClass->isEmbeddedClass) {
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
$mapping['inherited'] = $parentClass->name;
}
if (! isset($mapping['declared'])) {
@@ -470,6 +478,10 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
private function addNestedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass, $prefix)
{
foreach ($subClass->embeddedClasses as $property => $embeddableClass) {
if (isset($embeddableClass['inherited'])) {
continue;
}
$embeddableMetadata = $this->getMetadataFor($embeddableClass['class']);
$parentClass->mapEmbedded(
@@ -777,9 +789,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
*/
protected function isEntity(ClassMetadataInterface $class)
{
assert($class instanceof ClassMetadata);
return $class->isMappedSuperclass === false && $class->isEmbeddedClass === false;
return isset($class->isMappedSuperclass) && $class->isMappedSuperclass === false;
}
/**
@@ -794,3 +804,6 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
return $this->targetPlatform;
}
}
interface_exists(ClassMetadataInterface::class);
interface_exists(ReflectionService::class);

View File

@@ -20,14 +20,18 @@
namespace Doctrine\ORM\Mapping;
use BadMethodCallException;
use Doctrine\Instantiator\Instantiator;
use InvalidArgumentException;
use RuntimeException;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use ReflectionClass;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Instantiator\Instantiator;
use Doctrine\ORM\Cache\CacheException;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\ReflectionService;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionProperty;
use RuntimeException;
use function count;
use function explode;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-relational mapping metadata
@@ -251,7 +255,8 @@ class ClassMetadataInfo implements ClassMetadata
* The name of the custom repository class used for the entity class.
* (Optional).
*
* @var string
* @var string|null
* @psalm-var ?class-string
*/
public $customRepositoryClassName;
@@ -392,6 +397,8 @@ class ClassMetadataInfo implements ClassMetadata
* Whether a unique constraint should be generated for the column.
*
* @var array
*
* @psalm-var array<string, array{type: string, fieldName: string, columnName: string, inherited: class-string}>
*/
public $fieldMappings = [];
@@ -639,7 +646,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* The ReflectionProperty instances of the mapped class.
*
* @var \ReflectionProperty[]
* @var ReflectionProperty[]|null[]
*/
public $reflFields = [];
@@ -666,7 +673,9 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Gets the ReflectionProperties of the mapped class.
*
* @return array An array of ReflectionProperty instances.
* @return ReflectionProperty[]|null[] An array of ReflectionProperty instances.
*
* @psalm-return array<ReflectionProperty|null>
*/
public function getReflectionProperties()
{
@@ -678,7 +687,7 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param string $name
*
* @return \ReflectionProperty
* @return ReflectionProperty
*/
public function getReflectionProperty($name)
{
@@ -688,7 +697,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Gets the ReflectionProperty for the single identifier field.
*
* @return \ReflectionProperty
* @return ReflectionProperty
*
* @throws BadMethodCallException If the class has a composite identifier.
*/
@@ -804,7 +813,7 @@ class ClassMetadataInfo implements ClassMetadata
* - reflClass (ReflectionClass)
* - reflFields (ReflectionProperty array)
*
* @return array The names of all the fields that should be serialized.
* @return string[] The names of all the fields that should be serialized.
*/
public function __sleep()
{
@@ -914,7 +923,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Restores some state that can not be serialized/unserialized.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
* @param ReflectionService $reflService
*
* @return void
*/
@@ -975,7 +984,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 \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService The reflection service.
* @param ReflectionService $reflService The reflection service.
*
* @return void
*/
@@ -1037,7 +1046,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Validates lifecycle callbacks.
*
* @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
* @param ReflectionService $reflService
*
* @return void
*
@@ -1095,7 +1104,10 @@ class ClassMetadataInfo implements ClassMetadata
* @param string $fieldName
* @param array $cache
*
* @return array
* @return mixed[]
*
* @psalm-param array{usage: mixed, region: mixed} $cache
* @psalm-return array{usage: mixed, region: mixed}
*/
public function getAssociationCacheDefaults($fieldName, array $cache)
{
@@ -1444,9 +1456,25 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping.
*
* @return array The updated mapping.
* @return mixed[] The updated mapping.
*
* @throws MappingException If something is wrong with the mapping.
*
* @psalm-return array{
* mappedBy: mixed,
* inversedBy: mixed,
* isOwningSide: bool,
* sourceEntity: string,
* targetEntity: string,
* fieldName: mixed,
* fetch: mixed,
* cascade: array<array-key,string>,
* isCascadeRemove: bool,
* isCascadePersist: bool,
* isCascadeRefresh: bool,
* isCascadeMerge: bool,
* isCascadeDetach: bool
* }
*/
protected function _validateAndCompleteAssociationMapping(array $mapping)
{
@@ -1564,10 +1592,12 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping to validate & complete.
*
* @return array The validated & completed mapping.
* @return mixed[] The validated & completed mapping.
*
* @throws RuntimeException
* @throws MappingException
*
* @psalm-return array{isOwningSide: mixed, orphanRemoval: bool, isCascadeRemove: bool}
*/
protected function _validateAndCompleteOneToOneMapping(array $mapping)
{
@@ -1655,10 +1685,27 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping to validate and complete.
*
* @return array The validated and completed mapping.
* @return mixed[] The validated and completed mapping.
*
* @throws MappingException
* @throws InvalidArgumentException
*
* @psalm-return array{
* mappedBy: mixed,
* inversedBy: mixed,
* isOwningSide: bool,
* sourceEntity: string,
* targetEntity: string,
* fieldName: mixed,
* fetch: int|mixed,
* cascade: array<array-key,string>,
* isCascadeRemove: bool,
* isCascadePersist: bool,
* isCascadeRefresh: bool,
* isCascadeMerge: bool,
* isCascadeDetach: bool,
* orphanRemoval: bool
* }
*/
protected function _validateAndCompleteOneToManyMapping(array $mapping)
{
@@ -1682,9 +1729,11 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array $mapping The mapping to validate & complete.
*
* @return array The validated & completed mapping.
* @return mixed[] The validated & completed mapping.
*
* @throws \InvalidArgumentException
*
* @psalm-return array{isOwningSide: mixed, orphanRemoval: bool}
*/
protected function _validateAndCompleteManyToManyMapping(array $mapping)
{
@@ -1861,7 +1910,9 @@ class ClassMetadataInfo implements ClassMetadata
*
* @param array|null $fieldNames
*
* @return array
* @return mixed[]
*
* @psalm-return list<string>
*/
public function getColumnNames(array $fieldNames = null)
{
@@ -2142,6 +2193,13 @@ class ClassMetadataInfo implements ClassMetadata
$mapping = $this->associationMappings[$fieldName];
//if (isset($mapping['inherited']) && (count($overrideMapping) !== 1 || ! isset($overrideMapping['fetch']))) {
// TODO: Deprecate overriding the fetch mode via association override for 3.0,
// users should do this with a listener and a custom attribute/annotation
// TODO: Enable this exception in 2.8
//throw MappingException::illegalOverrideOfInheritedProperty($this->name, $fieldName);
//}
if (isset($overrideMapping['joinColumns'])) {
$mapping['joinColumns'] = $overrideMapping['joinColumns'];
}
@@ -2200,6 +2258,11 @@ class ClassMetadataInfo implements ClassMetadata
$mapping = $this->fieldMappings[$fieldName];
//if (isset($mapping['inherited'])) {
// TODO: Enable this exception in 2.8
//throw MappingException::illegalOverrideOfInheritedProperty($this->name, $fieldName);
//}
if (isset($mapping['id'])) {
$overrideMapping['id'] = $mapping['id'];
}
@@ -2297,7 +2360,7 @@ class ClassMetadataInfo implements ClassMetadata
if (isset($table['name'])) {
// Split schema and table name from a table name like "myschema.mytable"
if (strpos($table['name'], '.') !== false) {
list($this->table['schema'], $table['name']) = explode('.', $table['name'], 2);
[$this->table['schema'], $table['name']] = explode('.', $table['name'], 2);
}
if ($table['name'][0] === '`') {
@@ -2523,7 +2586,7 @@ class ClassMetadataInfo implements ClassMetadata
if (!isset($field['column'])) {
$fieldName = $field['name'];
if (strpos($fieldName, '.')) {
list(, $fieldName) = explode('.', $fieldName);
[, $fieldName] = explode('.', $fieldName);
}
$resultMapping['entities'][$key]['fields'][$k]['column'] = $fieldName;
@@ -2625,6 +2688,8 @@ class ClassMetadataInfo implements ClassMetadata
* @param string $repositoryClassName The class name of the custom mapper.
*
* @return void
*
* @psalm-param class-string $repositoryClassName
*/
public function setCustomRepositoryClass($repositoryClassName)
{
@@ -3253,6 +3318,8 @@ class ClassMetadataInfo implements ClassMetadata
* @param string|null $className
*
* @return string|null null if the input value is null
*
* @psalm-param ?class-string $className
*/
public function fullyQualifiedClassName($className)
{

View File

@@ -30,6 +30,8 @@ class DefaultEntityListenerResolver implements EntityListenerResolver
{
/**
* @var array Map to store entity listener instances.
*
* @psalm-var array<class-string, object>
*/
private $instances = [];

View File

@@ -20,12 +20,13 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
use Doctrine\ORM\Events;
use Doctrine\ORM\Mapping;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
use function interface_exists;
/**
* The AnnotationDriver reads the mapping metadata from docblock annotations.
@@ -39,12 +40,12 @@ use Doctrine\ORM\Mapping\MappingException;
class AnnotationDriver extends AbstractAnnotationDriver
{
/**
* {@inheritDoc}
* @var int[]
* @psalm-var array<class-string, int>
*/
protected $entityAnnotationClasses = [
Mapping\Entity::class => 1,
Mapping\MappedSuperclass::class => 2,
Mapping\Embeddable::class => 3,
];
/**
@@ -274,11 +275,8 @@ class AnnotationDriver extends AbstractAnnotationDriver
}
// Evaluate annotations on properties/fields
/* @var $property \ReflectionProperty */
foreach ($class->getProperties() as $property) {
if ($metadata->isMappedSuperclass && ! $property->isPrivate()
||
$metadata->isEmbeddedClass && $property->getDeclaringClass()->getName() !== $class->getName()
||
$metadata->isInheritedField($property->name)
||
@@ -344,7 +342,7 @@ class AnnotationDriver extends AbstractAnnotationDriver
'initialValue' => $seqGeneratorAnnot->initialValue
]
);
} else if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) {
} elseif ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Id\TableGenerator')) {
throw MappingException::tableIdGeneratorNotImplemented($className);
} else if ($customGeneratorAnnot = $this->reader->getPropertyAnnotation($property, Mapping\CustomIdGenerator::class)) {
$metadata->setCustomGeneratorDefinition(
@@ -507,7 +505,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
$hasMapping = false;
$listenerClass = new \ReflectionClass($listenerClassName);
/* @var $method \ReflectionMethod */
foreach ($listenerClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
// find method callbacks.
$callbacks = $this->getMethodCallbacks($method);
@@ -527,7 +524,6 @@ class AnnotationDriver extends AbstractAnnotationDriver
// Evaluate @HasLifecycleCallbacks annotation
if (isset($classAnnotations[Mapping\HasLifecycleCallbacks::class])) {
/* @var $method \ReflectionMethod */
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
foreach ($this->getMethodCallbacks($method) as $value) {
$metadata->addLifecycleCallback($value[0], $value[1]);
@@ -560,7 +556,7 @@ class AnnotationDriver extends AbstractAnnotationDriver
*
* @param \ReflectionMethod $method
*
* @return array
* @return callable[]
*/
private function getMethodCallbacks(\ReflectionMethod $method)
{
@@ -608,7 +604,17 @@ class AnnotationDriver extends AbstractAnnotationDriver
* Parse the given JoinColumn as array
*
* @param Mapping\JoinColumn $joinColumn
* @return array
*
* @return mixed[]
*
* @psalm-return array{
* name: string,
* unique: bool,
* nullable: bool,
* onDelete: mixed,
* columnDefinition: string,
* referencedColumnName: string
* }
*/
private function joinColumnToArray(Mapping\JoinColumn $joinColumn)
{
@@ -628,7 +634,20 @@ class AnnotationDriver extends AbstractAnnotationDriver
* @param string $fieldName
* @param Mapping\Column $column
*
* @return array
* @return mixed[]
*
* @psalm-return array{
* fieldName: string,
* type: mixed,
* scale: int,
* length: int,
* unique: bool,
* nullable: bool,
* precision: int,
* options?: mixed[],
* columnName?: string,
* columnDefinition?: string
* }
*/
private function columnToArray($fieldName, Mapping\Column $column)
{
@@ -674,3 +693,5 @@ class AnnotationDriver extends AbstractAnnotationDriver
return new self($reader, $paths);
}
}
interface_exists(ClassMetadata::class);

View File

@@ -20,15 +20,17 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Inflector\Inflector;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
use function interface_exists;
use function preg_replace;
/**
@@ -387,6 +389,22 @@ class DatabaseDriver implements MappingDriver
* @param \Doctrine\DBAL\Schema\Column $column
*
* @return array
*
* @psalm-return array{
* fieldName: string,
* columnName: string,
* type: string,
* nullable: bool,
* options?: array{
* unsigned?: bool,
* fixed?: bool,
* comment?: string,
* default?: string
* },
* precision?: int,
* scale?: int,
* length?: int|null
* }
*/
private function buildFieldMapping($tableName, Column $column)
{
@@ -487,7 +505,9 @@ class DatabaseDriver implements MappingDriver
*
* @param \Doctrine\DBAL\Schema\Table $table
*
* @return array
* @return ForeignKeyConstraint[]
*
* @psalm-return array<string, ForeignKeyConstraint>
*/
private function getTableForeignKeys(Table $table)
{
@@ -501,7 +521,7 @@ class DatabaseDriver implements MappingDriver
*
* @param \Doctrine\DBAL\Schema\Table $table
*
* @return array
* @return string[]
*/
private function getTablePrimaryKeys(Table $table)
{
@@ -555,3 +575,5 @@ class DatabaseDriver implements MappingDriver
return Inflector::camelize($columnName);
}
}
interface_exists(ClassMetadata::class);

View File

@@ -19,12 +19,12 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
/**
* {@inheritDoc}
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain instead
* @deprecated this driver will be removed. Use Doctrine\Persistence\Mapping\Driver\MappingDriverChain instead
*/
class DriverChain extends MappingDriverChain
{

View File

@@ -19,12 +19,12 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver as CommonPHPDriver;
use Doctrine\Persistence\Mapping\Driver\PHPDriver as CommonPHPDriver;
/**
* {@inheritDoc}
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver instead
* @deprecated this driver will be removed. Use Doctrine\Persistence\Mapping\Driver\PHPDriver instead
*/
class PHPDriver extends CommonPHPDriver
{

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator;
use Doctrine\Persistence\Mapping\Driver\SymfonyFileLocator;
/**
* XmlDriver that additionally looks for mapping information in a global file.

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator;
use Doctrine\Persistence\Mapping\Driver\SymfonyFileLocator;
/**
* YamlDriver that additionally looks for mapping information in a global file.

View File

@@ -19,12 +19,12 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver as CommonStaticPHPDriver;
use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver as CommonStaticPHPDriver;
/**
* {@inheritDoc}
*
* @deprecated this driver will be removed. Use Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver instead
* @deprecated this driver will be removed. Use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver instead
*/
class StaticPHPDriver extends CommonStaticPHPDriver
{

View File

@@ -20,12 +20,13 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Collections\Criteria;
use SimpleXMLElement;
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\ORM\Mapping\ClassMetadata as Metadata;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\FileDriver;
use SimpleXMLElement;
use function interface_exists;
/**
* XmlDriver is a metadata driver that enables mapping through XML files.
@@ -670,13 +671,12 @@ class XmlDriver extends FileDriver
*
* @param SimpleXMLElement $options The XML element.
*
* @return array The options array.
* @return mixed[] The options array.
*/
private function _parseOptions(SimpleXMLElement $options)
{
$array = [];
/* @var $option SimpleXMLElement */
foreach ($options as $option) {
if ($option->count()) {
$value = $this->_parseOptions($option->children());
@@ -705,7 +705,16 @@ class XmlDriver extends FileDriver
*
* @param SimpleXMLElement $joinColumnElement The XML element.
*
* @return array The mapping array.
* @return mixed[] The mapping array.
*
* @psalm-return array{
* name: string,
* referencedColumnName: string,
* unique?: bool,
* nullable?: bool,
* onDelete?: string,
* columnDefinition?: string
* }
*/
private function joinColumnToArray(SimpleXMLElement $joinColumnElement)
{
@@ -734,12 +743,24 @@ class XmlDriver extends FileDriver
}
/**
* Parses the given field as array.
*
* @param SimpleXMLElement $fieldMapping
*
* @return array
*/
* Parses the given field as array.
*
* @return mixed[]
*
* @psalm-return array{
* fieldName: string,
* type?: string,
* columnName?: string,
* length?: int,
* precision?: int,
* scale?: int,
* unique?: bool,
* nullable?: bool,
* version?: bool,
* columnDefinition?: string,
* options?: array
* }
*/
private function columnToArray(SimpleXMLElement $fieldMapping)
{
$mapping = [
@@ -794,7 +815,9 @@ class XmlDriver extends FileDriver
*
* @param SimpleXMLElement $cacheMapping
*
* @return array
* @return mixed[]
*
* @psalm-return array{usage: mixed, region: string|null}
*/
private function cacheToArray(SimpleXMLElement $cacheMapping)
{
@@ -820,12 +843,13 @@ class XmlDriver extends FileDriver
*
* @param SimpleXMLElement $cascadeElement The cascade element.
*
* @return array The list of cascade options.
* @return string[] The list of cascade options.
*
* @psalm-return list<string>
*/
private function _getCascadeMappings(SimpleXMLElement $cascadeElement)
{
$cascades = [];
/* @var $action SimpleXmlElement */
foreach ($cascadeElement->children() as $action) {
// According to the JPA specifications, XML uses "cascade-persist"
// instead of "persist". Here, both variations
@@ -879,3 +903,5 @@ class XmlDriver extends FileDriver
return ($flag == "true" || $flag == "1");
}
}
interface_exists(ClassMetadata::class);

View File

@@ -19,12 +19,13 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
use Doctrine\ORM\Mapping\ClassMetadata as Metadata;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\FileDriver;
use Symfony\Component\Yaml\Yaml;
use function interface_exists;
use function trigger_error;
/**
@@ -683,7 +684,17 @@ class YamlDriver extends FileDriver
*
* @param array $joinColumnElement The array join column element.
*
* @return array The mapping array.
* @return mixed[] The mapping array.
*
* @psalm-return array{
* referencedColumnName?: string,
* name?: string,
* fieldName?: string,
* unique?: bool,
* nullable?: bool,
* onDelete?: mixed,
* columnDefinition?: mixed
* }
*/
private function joinColumnToArray($joinColumnElement)
{
@@ -725,7 +736,21 @@ class YamlDriver extends FileDriver
* @param string $fieldName
* @param array $column
*
* @return array
* @return mixed[]
*
* @psalm-return array{
* fieldName: string,
* type?: string,
* columnName?: mixed,
* length?: mixed,
* precision?: mixed,
* scale?: mixed,
* unique?: bool,
* options?: mixed,
* nullable?: mixed,
* version?: mixed,
* columnDefinition?: mixed
* }
*/
private function columnToArray($fieldName, $column)
{
@@ -786,9 +811,12 @@ class YamlDriver extends FileDriver
/**
* Parse / Normalize the cache configuration
*
* @param array $cacheMapping
* @param mixed[] $cacheMapping
*
* @return array
* @return mixed[]
*
* @psalm-param array{usage: mixed, region: null|string} $cacheMapping
* @psalm-return array{usage: mixed, region: null|string}
*/
private function cacheToArray($cacheMapping)
{
@@ -817,3 +845,5 @@ class YamlDriver extends FileDriver
return Yaml::parse(file_get_contents($file));
}
}
interface_exists(ClassMetadata::class);

View File

@@ -34,6 +34,8 @@ interface EntityListenerResolver
* @param string $className The fully-qualified class name
*
* @return void
*
* @psalm-param class-string $className
*/
function clear($className = null);
@@ -43,6 +45,8 @@ interface EntityListenerResolver
* @param string $className The fully-qualified class name
*
* @return object An entity listener
*
* @psalm-param class-string $className
*/
function resolve($className);

View File

@@ -19,6 +19,8 @@
namespace Doctrine\ORM\Mapping;
use function sprintf;
/**
* A MappingException indicates that something is wrong with the mapping setup.
*
@@ -820,4 +822,16 @@ class MappingException extends \Doctrine\ORM\ORMException
)
);
}
public static function illegalOverrideOfInheritedProperty($className, $propertyName)
{
return new self(
sprintf(
'Override for %s::%s is only allowed for attributes/associations ' .
'declared on a mapped superclass or a trait.',
$className,
$propertyName
)
);
}
}

View File

@@ -19,7 +19,7 @@
namespace Doctrine\ORM\Mapping\Reflection;
use Doctrine\Common\Persistence\Mapping\ReflectionService;
use Doctrine\Persistence\Mapping\ReflectionService;
use ReflectionClass;
use ReflectionProperty;
@@ -52,9 +52,11 @@ final class ReflectionPropertiesGetter
}
/**
* @param $className
* @param string $className
*
* @return ReflectionProperty[] indexed by property internal name
*
* @psalm-param class-string $className
*/
public function getProperties($className)
{
@@ -79,8 +81,10 @@ final class ReflectionPropertiesGetter
* @param string $className
*
* @return ReflectionClass[]
*
* @psalm-return list<ReflectionClass>
*/
private function getHierarchyClasses($className)
private function getHierarchyClasses($className) : array
{
$classes = [];
$parentClassName = $className;
@@ -97,13 +101,17 @@ final class ReflectionPropertiesGetter
return $classes;
}
// phpcs:disable SlevomatCodingStandard.Classes.UnusedPrivateElements.UnusedMethod
/**
* @param ReflectionClass $reflectionClass
*
* @return ReflectionProperty[]
*
* @psalm-return array<string, ReflectionProperty>
*/
private function getClassProperties(ReflectionClass $reflectionClass)
private function getClassProperties(ReflectionClass $reflectionClass) : array
{
// phpcs:enable SlevomatCodingStandard.Classes.UnusedPrivateElements.UnusedMethod
$properties = $reflectionClass->getProperties();
return array_filter(

View File

@@ -37,9 +37,9 @@ final class NativeQuery extends AbstractQuery
*
* @param string $sql
*
* @return NativeQuery This query instance.
* @return self This query instance.
*/
public function setSQL($sql)
public function setSQL($sql) : self
{
$this->_sql = $sql;

View File

@@ -20,7 +20,9 @@
namespace Doctrine\ORM;
use Doctrine\Common\Cache\Cache as CacheDriver;
use Doctrine\Persistence\ObjectRepository;
use Exception;
use function sprintf;
/**
* Base exception class for all ORM exceptions.
@@ -108,7 +110,7 @@ class ORMException extends Exception
* @param string $given
* @param string $expected
*
* @return \Doctrine\ORM\ORMInvalidArgumentException
* @return \Doctrine\ORM\ORMException
*/
public static function unexpectedAssociationValue($class, $association, $given, $expected)
{
@@ -295,7 +297,11 @@ class ORMException extends Exception
*/
public static function invalidEntityRepository($className)
{
return new self("Invalid repository class '".$className."'. It must be a Doctrine\Common\Persistence\ObjectRepository.");
return new self(sprintf(
"Invalid repository class '%s'. It must be a %s.",
$className,
ObjectRepository::class
));
}
/**

View File

@@ -36,7 +36,7 @@ class OptimisticLockException extends ORMException
/**
* @param string $msg
* @param object $entity
* @param object|null $entity
*/
public function __construct($msg, $entity)
{

View File

@@ -337,6 +337,8 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
/**
* {@inheritdoc}
*
* @return object
*/
public function remove($key)
{
@@ -510,6 +512,8 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
/**
* {@inheritdoc}
*
* @return object
*/
public function offsetUnset($offset)
{
@@ -569,9 +573,11 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
* Internal note: Tried to implement Serializable first but that did not work well
* with circular references. This solution seems simpler and works well.
*
* @return array
* @return string[]
*
* @psalm-return array{0: string, 1: string}
*/
public function __sleep()
public function __sleep() : array
{
return ['collection', 'initialized'];
}

View File

@@ -68,8 +68,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
return; // ignore inverse side
}
list($deleteSql, $deleteTypes) = $this->getDeleteRowSQL($collection);
list($insertSql, $insertTypes) = $this->getInsertRowSQL($collection);
[$deleteSql, $deleteTypes] = $this->getDeleteRowSQL($collection);
[$insertSql, $insertTypes] = $this->getInsertRowSQL($collection);
foreach ($collection->getDeleteDiff() as $element) {
$this->conn->executeUpdate(
@@ -136,7 +136,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$types[] = PersisterHelper::getTypeOfColumn($referencedName, $sourceClass, $this->em);
}
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping);
[$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($mapping);
if ($filterSql) {
$conditions[] = $filterSql;
@@ -188,7 +188,11 @@ class ManyToManyPersister extends AbstractCollectionPersister
throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections.");
}
list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictionsWithKey($collection, $key, true);
[$quotedJoinTable, $whereClauses, $params, $types] = $this->getJoinTableRestrictionsWithKey(
$collection,
$key,
true
);
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
@@ -204,7 +208,11 @@ class ManyToManyPersister extends AbstractCollectionPersister
return false;
}
list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictions($collection, $element, true);
[$quotedJoinTable, $whereClauses, $params, $types] = $this->getJoinTableRestrictions(
$collection,
$element,
true
);
$sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses);
@@ -288,6 +296,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
* @return string[] ordered tuple:
* - JOIN condition to add to the SQL
* - WHERE condition to add to the SQL
*
* @psalm-return array{0: string, 1: string}
*/
public function getFilterSql($mapping)
{
@@ -335,7 +345,9 @@ class ManyToManyPersister extends AbstractCollectionPersister
*
* @param array $mapping
*
* @return array
* @return string[]
*
* @psalm-return list<string>
*/
protected function getOnConditionSQL($mapping)
{
@@ -361,9 +373,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
}
/**
* {@inheritdoc}
*
* @override
* @return string
*/
protected function getDeleteSQL(PersistentCollection $collection)
{
@@ -381,10 +391,9 @@ class ManyToManyPersister extends AbstractCollectionPersister
}
/**
* {@inheritdoc}
*
* Internal note: Order of the parameters must be the same as the order of the columns in getDeleteSql.
* @override
*
* @return mixed[]
*/
protected function getDeleteSQLParameters(PersistentCollection $collection)
{
@@ -416,6 +425,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
*
* @return string[]|string[][] ordered tuple containing the SQL to be executed and an array
* of types for bound parameters
*
* @psalm-return array{0: string, 1: list<string>}
*/
protected function getDeleteRowSQL(PersistentCollection $collection)
{
@@ -452,6 +463,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
* @param mixed $element
*
* @return array
*
* @psalm-return list<mixed>
*/
protected function getDeleteRowSQLParameters(PersistentCollection $collection, $element)
{
@@ -465,6 +478,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
*
* @return string[]|string[][] ordered tuple containing the SQL to be executed and an array
* of types for bound parameters
*
* @psalm-return array{0: string, 1: list<string>}
*/
protected function getInsertRowSQL(PersistentCollection $collection)
{
@@ -503,6 +518,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
* @param mixed $element
*
* @return array
*
* @psalm-return list<mixed>
*/
protected function getInsertRowSQLParameters(PersistentCollection $collection, $element)
{
@@ -516,7 +533,9 @@ class ManyToManyPersister extends AbstractCollectionPersister
* @param \Doctrine\ORM\PersistentCollection $collection
* @param object $element
*
* @return array
* @return mixed[]
*
* @psalm-return list<mixed>
*/
private function collectJoinTableColumnParameters(PersistentCollection $collection, $element)
{
@@ -564,6 +583,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
* - where clauses to be added for filtering
* - parameters to be bound for filtering
* - types of the parameters to be bound for filtering
*
* @psalm-return array{0: string, 1: list<string>, 2: list<mixed>, 3: list<string>}
*/
private function getJoinTableRestrictionsWithKey(PersistentCollection $collection, $key, $addFilters)
{
@@ -628,7 +649,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
}
if ($addFilters) {
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
[$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($filterMapping);
if ($filterSql) {
$quotedJoinTable .= ' ' . $joinTargetEntitySQL;
@@ -649,6 +670,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
* - where clauses to be added for filtering
* - parameters to be bound for filtering
* - types of the parameters to be bound for filtering
*
* @psalm-return array{0: string, 1: list<string>, 2: list<mixed>, 3: list<string>}
*/
private function getJoinTableRestrictions(PersistentCollection $collection, $element, $addFilters)
{
@@ -694,7 +717,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
if ($addFilters) {
$quotedJoinTable .= ' t';
list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($filterMapping);
[$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($filterMapping);
if ($filterSql) {
$quotedJoinTable .= ' ' . $joinTargetEntitySQL;
@@ -725,7 +748,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$valueVisitor->dispatch($expression);
list(, $types) = $valueVisitor->getParamsAndTypes();
[, $types] = $valueVisitor->getParamsAndTypes();
return $types;
}

View File

@@ -36,6 +36,8 @@ class OneToManyPersister extends AbstractCollectionPersister
{
/**
* {@inheritdoc}
*
* @return int|null
*/
public function delete(PersistentCollection $collection)
{

View File

@@ -92,7 +92,6 @@ class BasicEntityPersister implements EntityPersister
*/
static private $comparisonMap = [
Comparison::EQ => '= %s',
Comparison::IS => '= %s',
Comparison::NEQ => '!= %s',
Comparison::GT => '> %s',
Comparison::GTE => '>= %s',
@@ -361,6 +360,11 @@ class BasicEntityPersister implements EntityPersister
return Type::getType($fieldMapping['type'])->convertToPHPValue($value, $this->platform);
}
/**
* @return int[]|null[]|string[]
*
* @psalm-return list<int|null|string>
*/
private function extractIdentifierTypes(array $id, ClassMetadata $versionedClass) : array
{
$types = [];
@@ -448,9 +452,9 @@ class BasicEntityPersister implements EntityPersister
foreach ($this->class->identifier as $idField) {
if ( ! isset($this->class->associationMappings[$idField])) {
$params[] = $identifier[$idField];
$types[] = $this->class->fieldMappings[$idField]['type'];
$where[] = $this->quoteStrategy->getColumnName($idField, $this->class, $this->platform);
$params[] = $identifier[$idField];
$types[] = $this->class->fieldMappings[$idField]['type'];
$where[] = $this->quoteStrategy->getColumnName($idField, $this->class, $this->platform);
continue;
}
@@ -602,7 +606,9 @@ class BasicEntityPersister implements EntityPersister
*
* @param object $entity The entity for which to prepare the data.
*
* @return array The prepared data.
* @return mixed[][] The prepared data.
*
* @psalm-return array<string, array<array-key, mixed|null>>
*/
protected function prepareUpdateData($entity)
{
@@ -689,9 +695,11 @@ class BasicEntityPersister implements EntityPersister
*
* @param object $entity The entity for which to prepare the data.
*
* @return array The prepared data for the tables to update.
* @return mixed[][] The prepared data for the tables to update.
*
* @see prepareUpdateData
*
* @psalm-return array<string, mixed[]>
*/
protected function prepareInsertData($entity)
{
@@ -714,7 +722,7 @@ class BasicEntityPersister implements EntityPersister
$this->switchPersisterContext(null, $limit);
$sql = $this->getSelectSQL($criteria, $assoc, $lockMode, $limit, null, $orderBy);
list($params, $types) = $this->expandParameters($criteria);
[$params, $types] = $this->expandParameters($criteria);
$stmt = $this->conn->executeQuery($sql, $params, $types);
if ($entity !== null) {
@@ -806,7 +814,7 @@ class BasicEntityPersister implements EntityPersister
public function refresh(array $id, $entity, $lockMode = null)
{
$sql = $this->getSelectSQL($id, null, $lockMode);
list($params, $types) = $this->expandParameters($id);
[$params, $types] = $this->expandParameters($id);
$stmt = $this->conn->executeQuery($sql, $params, $types);
$hydrator = $this->em->newHydrator(Query::HYDRATE_OBJECT);
@@ -820,7 +828,7 @@ class BasicEntityPersister implements EntityPersister
{
$sql = $this->getCountSQL($criteria);
list($params, $types) = ($criteria instanceof Criteria)
[$params, $types] = $criteria instanceof Criteria
? $this->expandCriteriaParameters($criteria)
: $this->expandParameters($criteria);
@@ -837,7 +845,7 @@ class BasicEntityPersister implements EntityPersister
$offset = $criteria->getFirstResult();
$query = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy);
list($params, $types) = $this->expandCriteriaParameters($criteria);
[$params, $types] = $this->expandCriteriaParameters($criteria);
$stmt = $this->conn->executeQuery($query, $params, $types);
$hydrator = $this->em->newHydrator(($this->currentPersisterContext->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
@@ -863,14 +871,14 @@ class BasicEntityPersister implements EntityPersister
$valueVisitor->dispatch($expression);
list($params, $types) = $valueVisitor->getParamsAndTypes();
[$params, $types] = $valueVisitor->getParamsAndTypes();
foreach ($params as $param) {
$sqlParams = array_merge($sqlParams, $this->getValues($param));
}
foreach ($types as $type) {
list ($field, $value) = $type;
[$field, $value] = $type;
$sqlTypes = array_merge($sqlTypes, $this->getTypes($field, $value, $this->class));
}
@@ -885,7 +893,7 @@ class BasicEntityPersister implements EntityPersister
$this->switchPersisterContext($offset, $limit);
$sql = $this->getSelectSQL($criteria, null, null, $limit, $offset, $orderBy);
list($params, $types) = $this->expandParameters($criteria);
[$params, $types] = $this->expandParameters($criteria);
$stmt = $this->conn->executeQuery($sql, $params, $types);
$hydrator = $this->em->newHydrator(($this->currentPersisterContext->selectJoinSql) ? Query::HYDRATE_OBJECT : Query::HYDRATE_SIMPLEOBJECT);
@@ -955,11 +963,11 @@ class BasicEntityPersister implements EntityPersister
/**
* {@inheritdoc}
*/
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
{
$stmt = $this->getManyToManyStatement($assoc, $sourceEntity);
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
return $this->loadCollectionFromStatement($assoc, $stmt, $collection);
}
/**
@@ -1030,7 +1038,7 @@ class BasicEntityPersister implements EntityPersister
}
$sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset);
list($params, $types) = $this->expandToManyParameters($parameters);
[$params, $types] = $this->expandToManyParameters($parameters);
return $this->conn->executeQuery($sql, $params, $types);
}
@@ -1134,7 +1142,7 @@ class BasicEntityPersister implements EntityPersister
*
* @throws \Doctrine\ORM\ORMException
*/
protected final function getOrderBySQL(array $orderBy, $baseTableAlias)
final protected function getOrderBySQL(array $orderBy, $baseTableAlias) : string
{
$orderByList = [];
@@ -1419,7 +1427,9 @@ class BasicEntityPersister implements EntityPersister
* Subclasses should override this method to alter or change the list of
* columns placed in the INSERT statements used by the persister.
*
* @return array The list of columns.
* @return string[] The list of columns.
*
* @psalm-return list<string>
*/
protected function getInsertColumnList()
{
@@ -1536,7 +1546,7 @@ class BasicEntityPersister implements EntityPersister
. $where
. $lockSql;
list($params, $types) = $this->expandParameters($criteria);
[$params, $types] = $this->expandParameters($criteria);
$this->conn->executeQuery($sql, $params, $types);
}
@@ -1544,7 +1554,7 @@ class BasicEntityPersister implements EntityPersister
/**
* Gets the FROM and optionally JOIN conditions to lock the entity managed by this persister.
*
* @param integer $lockMode One of the Doctrine\DBAL\LockMode::* constants.
* @param int|null $lockMode One of the Doctrine\DBAL\LockMode::* constants.
*
* @return string
*/
@@ -1656,13 +1666,13 @@ class BasicEntityPersister implements EntityPersister
* @return string[]
*
* @throws \Doctrine\ORM\ORMException
*
* @psalm-return list<string>
*/
private function getSelectConditionStatementColumnSQL($field, $assoc = null)
{
if (isset($this->class->fieldMappings[$field])) {
$className = (isset($this->class->fieldMappings[$field]['inherited']))
? $this->class->fieldMappings[$field]['inherited']
: $this->class->name;
$className = $this->class->fieldMappings[$field]['inherited'] ?? $this->class->name;
return [$this->getSQLTableAlias($className) . '.' . $this->quoteStrategy->getColumnName($field, $this->class, $this->platform)];
}
@@ -1753,11 +1763,11 @@ class BasicEntityPersister implements EntityPersister
/**
* {@inheritdoc}
*/
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $collection)
{
$stmt = $this->getOneToManyStatement($assoc, $sourceEntity);
return $this->loadCollectionFromStatement($assoc, $stmt, $coll);
return $this->loadCollectionFromStatement($assoc, $stmt, $collection);
}
/**
@@ -1813,7 +1823,7 @@ class BasicEntityPersister implements EntityPersister
}
$sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset);
list($params, $types) = $this->expandToManyParameters($parameters);
[$params, $types] = $this->expandToManyParameters($parameters);
return $this->conn->executeQuery($sql, $params, $types);
}
@@ -1847,8 +1857,9 @@ class BasicEntityPersister implements EntityPersister
* - value to be bound
* - class to which the field belongs to
*
* @return mixed[][]
*
* @return array
* @psalm-return array{0: array, 1: list<mixed>}
*/
private function expandToManyParameters($criteria)
{
@@ -1874,9 +1885,11 @@ class BasicEntityPersister implements EntityPersister
* @param mixed $value
* @param ClassMetadata $class
*
* @return array
* @return int[]|null[]|string[]
*
* @throws \Doctrine\ORM\Query\QueryException
*
* @psalm-return list<int|null|string>
*/
private function getTypes($field, $value, ClassMetadata $class)
{
@@ -1989,11 +2002,11 @@ class BasicEntityPersister implements EntityPersister
. $this->getLockTablesSql(null)
. ' WHERE ' . $this->getSelectConditionSQL($criteria);
list($params, $types) = $this->expandParameters($criteria);
[$params, $types] = $this->expandParameters($criteria);
if (null !== $extraConditions) {
$sql .= ' AND ' . $this->getSelectConditionCriteriaSQL($extraConditions);
list($criteriaParams, $criteriaTypes) = $this->expandCriteriaParameters($extraConditions);
[$criteriaParams, $criteriaTypes] = $this->expandCriteriaParameters($extraConditions);
$params = array_merge($params, $criteriaParams);
$types = array_merge($types, $criteriaTypes);
@@ -2026,7 +2039,9 @@ class BasicEntityPersister implements EntityPersister
}
/**
* {@inheritdoc}
* @param string $columnName
*
* @return string
*/
public function getSQLColumnAlias($columnName)
{

View File

@@ -18,8 +18,9 @@
*/
namespace Doctrine\ORM\Persisters\Entity;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\Mapping\ClassMetadata;
/**
* A swappable persister context to use as a container for the current

View File

@@ -86,7 +86,7 @@ interface EntityPersister
/**
* Expands the parameters from the given criteria and use the correct binding types if found.
*
* @param $criteria
* @param string[] $criteria
*
* @return array
*/

View File

@@ -27,6 +27,8 @@ use Doctrine\DBAL\Types\Type;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Utility\PersisterHelper;
use function array_combine;
/**
* The joined subclass persister maps a single entity instance to several tables in the
* database as it is defined by the <tt>Class Table Inheritance</tt> strategy.

View File

@@ -93,7 +93,9 @@ class SqlValueVisitor extends ExpressionVisitor
/**
* Returns the Parameters and Types necessary for matching the last visited expression.
*
* @return array
* @return mixed[][]
*
* @psalm-return array{0: array, 1: array}
*/
public function getParamsAndTypes()
{

View File

@@ -19,7 +19,6 @@
namespace Doctrine\ORM\Proxy;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Proxy\AbstractProxyFactory;
use Doctrine\Common\Proxy\Proxy as BaseProxy;
use Doctrine\Common\Proxy\ProxyDefinition;
@@ -29,6 +28,8 @@ use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use Doctrine\ORM\EntityNotFoundException;
use Doctrine\ORM\Utility\IdentifierFlattener;
use Doctrine\Persistence\Mapping\ClassMetadata;
use function interface_exists;
/**
* This factory is used to create proxy objects for entities at runtime.
@@ -118,12 +119,11 @@ class ProxyFactory extends AbstractProxyFactory
/**
* Creates a closure capable of initializing a proxy
*
* @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
* @param \Doctrine\ORM\Persisters\Entity\EntityPersister $entityPersister
*
* @return \Closure
*
* @throws \Doctrine\ORM\EntityNotFoundException
*
* @psalm-return \Closure(BaseProxy):void
*/
private function createInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister)
{
@@ -172,12 +172,11 @@ class ProxyFactory extends AbstractProxyFactory
/**
* Creates a closure capable of finalizing state a cloned proxy
*
* @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
* @param \Doctrine\ORM\Persisters\Entity\EntityPersister $entityPersister
*
* @return \Closure
*
* @throws \Doctrine\ORM\EntityNotFoundException
*
* @psalm-return \Closure(BaseProxy):void
*/
private function createCloner(ClassMetadata $classMetadata, EntityPersister $entityPersister)
{
@@ -211,3 +210,5 @@ class ProxyFactory extends AbstractProxyFactory
};
}
}
interface_exists(ClassMetadata::class);

View File

@@ -22,6 +22,9 @@ namespace Doctrine\ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\Mapping\ClassMetadata;
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\Parameter;
use Doctrine\ORM\Query\ParameterTypeInferer;
@@ -213,9 +216,7 @@ final class Query extends AbstractQuery
/**
* Returns the corresponding AST for this DQL query.
*
* @return \Doctrine\ORM\Query\AST\SelectStatement |
* \Doctrine\ORM\Query\AST\UpdateStatement |
* \Doctrine\ORM\Query\AST\DeleteStatement
* @return SelectStatement|UpdateStatement|DeleteStatement
*/
public function getAST()
{
@@ -325,7 +326,7 @@ final class Query extends AbstractQuery
$this->evictEntityCacheRegion();
}
list($sqlParams, $types) = $this->processParameterMappings($paramMappings);
[$sqlParams, $types] = $this->processParameterMappings($paramMappings);
$this->evictResultSetCache(
$executor,
@@ -364,11 +365,11 @@ final class Query extends AbstractQuery
{
$AST = $this->getAST();
if ($AST instanceof \Doctrine\ORM\Query\AST\SelectStatement) {
if ($AST instanceof SelectStatement) {
throw new QueryException('The hint "HINT_CACHE_EVICT" is not valid for select statements.');
}
$className = ($AST instanceof \Doctrine\ORM\Query\AST\DeleteStatement)
$className = $AST instanceof DeleteStatement
? $AST->deleteClause->abstractSchemaName
: $AST->updateClause->abstractSchemaName;
@@ -380,11 +381,13 @@ final class Query extends AbstractQuery
*
* @param array $paramMappings
*
* @return array
* @return mixed[][]
*
* @throws Query\QueryException
*
* @psalm-return array{0: list<mixed>, 1: array}
*/
private function processParameterMappings($paramMappings)
private function processParameterMappings($paramMappings) : array
{
$sqlParams = [];
$types = [];
@@ -429,7 +432,11 @@ final class Query extends AbstractQuery
return [$sqlParams, $types];
}
/** @return mixed[] tuple of (value, type) */
/**
* @return mixed[] tuple of (value, type)
*
* @psalm-return array{0: mixed, 1: mixed}
*/
private function resolveParameterValue(Parameter $parameter) : array
{
if ($parameter->typeWasSpecified()) {
@@ -466,9 +473,9 @@ final class Query extends AbstractQuery
*
* @param \Doctrine\Common\Cache\Cache|null $queryCache Cache driver.
*
* @return Query This query instance.
* @return self This query instance.
*/
public function setQueryCacheDriver($queryCache)
public function setQueryCacheDriver($queryCache) : self
{
$this->_queryCache = $queryCache;
@@ -480,9 +487,9 @@ final class Query extends AbstractQuery
*
* @param boolean $bool
*
* @return Query This query instance.
* @return self This query instance.
*/
public function useQueryCache($bool)
public function useQueryCache($bool) : self
{
$this->_useQueryCache = $bool;
@@ -509,9 +516,9 @@ final class Query extends AbstractQuery
*
* @param integer $timeToLive How long the cache entry is valid.
*
* @return Query This query instance.
* @return self This query instance.
*/
public function setQueryCacheLifetime($timeToLive)
public function setQueryCacheLifetime($timeToLive) : self
{
if ($timeToLive !== null) {
$timeToLive = (int) $timeToLive;
@@ -537,9 +544,9 @@ final class Query extends AbstractQuery
*
* @param boolean $expire Whether or not to force query cache expiration.
*
* @return Query This query instance.
* @return self This query instance.
*/
public function expireQueryCache($expire = true)
public function expireQueryCache($expire = true) : self
{
$this->_expireQueryCache = $expire;
@@ -571,10 +578,8 @@ final class Query extends AbstractQuery
* Sets a DQL query string.
*
* @param string $dqlQuery DQL Query.
*
* @return \Doctrine\ORM\AbstractQuery
*/
public function setDQL($dqlQuery)
public function setDQL($dqlQuery) : self
{
if ($dqlQuery !== null) {
$this->_dql = $dqlQuery;
@@ -626,9 +631,9 @@ final class Query extends AbstractQuery
*
* @param int|null $firstResult The first result to return.
*
* @return Query This query object.
* @return self This query object.
*/
public function setFirstResult($firstResult)
public function setFirstResult($firstResult) : self
{
$this->_firstResult = $firstResult;
$this->_state = self::STATE_DIRTY;
@@ -652,9 +657,9 @@ final class Query extends AbstractQuery
*
* @param integer|null $maxResults
*
* @return Query This query object.
* @return self This query object.
*/
public function setMaxResults($maxResults)
public function setMaxResults($maxResults) : self
{
$this->_maxResults = $maxResults;
$this->_state = self::STATE_DIRTY;
@@ -716,11 +721,9 @@ final class Query extends AbstractQuery
*
* @param int $lockMode
*
* @return Query
*
* @throws TransactionRequiredException
*/
public function setLockMode($lockMode)
public function setLockMode($lockMode) : self
{
if (in_array($lockMode, [LockMode::NONE, LockMode::PESSIMISTIC_READ, LockMode::PESSIMISTIC_WRITE], true)) {
if ( ! $this->_em->getConnection()->isTransactionActive()) {

View File

@@ -105,7 +105,7 @@ class TrimFunction extends FunctionNode
}
/**
* @return integer
* @return int
*/
private function getTrimMode()
{

View File

@@ -48,4 +48,4 @@ class ParenthesisExpression extends Node
{
return $walker->walkParenthesisExpression($this);
}
}
}

View File

@@ -32,7 +32,7 @@ namespace Doctrine\ORM\Query\AST;
class SimpleSelectExpression extends Node
{
/**
* @var Node
* @var Node|string
*/
public $expression;
@@ -42,7 +42,7 @@ class SimpleSelectExpression extends Node
public $fieldIdentificationVariable;
/**
* @param Node $expression
* @param Node|string $expression
*/
public function __construct($expression)
{

View File

@@ -31,7 +31,7 @@ namespace Doctrine\ORM\Query\AST;
class WhereClause extends Node
{
/**
* @var ConditionalExpression
* @var ConditionalExpression|ConditionalTerm
*/
public $conditionalExpression;

View File

@@ -34,7 +34,7 @@ use Doctrine\DBAL\Cache\QueryCacheProfile;
abstract class AbstractSqlExecutor
{
/**
* @var array
* @var mixed[]|string
*/
protected $_sqlStatements;
@@ -46,7 +46,7 @@ abstract class AbstractSqlExecutor
/**
* Gets the SQL statements that are executed by the executor.
*
* @return array All the SQL update statements.
* @return mixed[]|string All the SQL update statements.
*/
public function getSqlStatements()
{

View File

@@ -22,6 +22,8 @@ namespace Doctrine\ORM\Query\Exec;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Query\AST;
use Doctrine\ORM\Query\AST\DeleteStatement;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Utility\PersisterHelper;
use Throwable;
@@ -57,8 +59,8 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
* Internal note: Any SQL construction and preparation takes place in the constructor for
* best performance. With a query cache the executor will be cached.
*
* @param \Doctrine\ORM\Query\AST\Node $AST The root AST node of the DQL query.
* @param \Doctrine\ORM\Query\SqlWalker $sqlWalker The walker used for SQL generation from the AST.
* @param DeleteStatement $AST The root AST node of the DQL query.
* @param SqlWalker $sqlWalker The walker used for SQL generation from the AST.
*/
public function __construct(AST\Node $AST, $sqlWalker)
{
@@ -116,6 +118,8 @@ class MultiTableDeleteExecutor extends AbstractSqlExecutor
/**
* {@inheritDoc}
*
* @return int
*/
public function execute(Connection $conn, array $params, array $types)
{

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