Compare commits

...

64 Commits

Author SHA1 Message Date
Grégoire Paris 7b24275346 Merge pull request #9218 from Florian-Varrin/patch-1
Fix typo assumptio--> assumption
2021-12-03 13:27:05 +01:00
Florian Varrin ed1a576305 Fix typo assumptio--> assumption 2021-12-03 11:39:59 +01:00
Alexander M. Turek 15ec77fa79 Suppress Psalm's ReservedWord errors (#9212) 2021-11-30 20:20:27 +01:00
Alexander M. Turek cac2acae07 Psalm 4.13.1, PHPStan 1.2.0 (#9204) 2021-11-28 00:50:56 +01:00
Grégoire Paris 146b465ec1 Merge pull request #9198 from laryjulien/fix-fieldmapping-definition
Add a psalm type for field mapping
2021-11-23 21:10:18 +01:00
Julien LARY 5aba762a33 Add a psalm type for field mapping
Field mapping have different definitions
in property definition and method return.
As suggested in issue and to avoid further desynchronization,
a psalm type has been created.
Fixes #9193
2021-11-23 18:05:47 +01:00
Simon Podlipsky a663dda869 Use equal to instead of equal of in assertSqlGeneration() (#9195) 2021-11-20 21:27:46 +01:00
Thomas Landauer db14f0fa89 Adding Attributes code block (#9161)
Just that there is some real-world example somewhere ;-) see https://github.com/doctrine/orm/issues/9020#issuecomment-955582801
2021-11-20 18:14:49 +01:00
Vincent Langlet 9a74ae6280 Fix discriminatorColumn phpdoc (#9168) 2021-11-11 23:01:34 +01:00
Grégoire Paris 32eb38ebd9 Merge pull request #9181 from greg0ire/fix-broken-build
Remove similar assertions for other platforms
2021-11-11 16:20:53 +01:00
Thomas Landauer 176fbedc69 Fine-tuning codeblock (#9176)
* Deleting "Not needed for XML and YAML mapping" - this was stupid of me, since *all* annotations are obviously not needed in XML&YAML ;-)
* Shortening the @Column annotation, for consistency with the following event handlers
* Removing some blank lines from XML, for consistency with YAML
* Adding PHP Attributes
2021-11-10 22:43:09 +01:00
Grégoire Paris 1b15af44b6 Remove similar assertions for other platforms
Testing with several platforms should not increase code coverage here,
since the DBAL is responsible for providing the concat expression for
each platform.

Moreover, whenever that concat expression changes for one of the tested
platforms, this test will break.

In doctrine/dbal 3.2, that is the case for SQLServer2012Platform, which
means this test no longer passes.
2021-11-08 21:21:41 +01:00
Grégoire Paris 8336420a26 Merge pull request #9153 from armenio/2.10.x
Infer type from field instead of column
2021-11-08 07:45:07 +01:00
Thomas Landauer a6b7569d7a Fixing more links (#9154)
* Fixing more links

The first two I missed in https://github.com/doctrine/orm/pull/9151
The third is probably older.
Shouldn't the chapter name be displayed as link text by default?? Are you sure that everything is set up correctly with the parser?

* Update architecture.rst

* Update getting-started.rst

* Update events.rst
2021-11-06 20:49:54 +01:00
Rafael Armenio 9e37c788ef Infer type from field instead of column
getTypeOfColumn() relies on getTypeOfField(), and does not suffer from
mismatching issues caused by quoting, because you cannot quote a field.
Since a field can be composite, that method returns an array, hence why we
need to select the first element.
2021-11-05 13:58:53 -03:00
Grégoire Paris ca0a6bbf71 Merge pull request #9167 from derrabus/bump/phpstan
PHPStan 1.0.1
2021-11-03 21:15:19 +01:00
Grégoire Paris a3da3d78d4 Merge pull request #9159 from ThomasLandauer/patch-10
Merging Lifecycle Callbacks code samples for PHP + XML + YAML
2021-11-03 21:13:53 +01:00
Alexander M. Turek e1c2d2e65d PHPStan 1.0.1
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-11-02 20:41:48 +01:00
Alexander Schranz 6f194eeabf Remove reverted bc break (#9166) 2021-11-01 13:56:12 +01:00
Grégoire Paris 16cbc16998 Document BC break (#9143)
Closes #9141
2021-10-30 19:10:25 +02:00
Thomas Landauer 5e6608b48e Update events.rst 2021-10-30 13:48:03 +02:00
Grégoire Paris 94bc137526 Merge pull request #9123 from phansys/quotes_in_column_names
Add XSD "orm:columntoken" type in order to support reserved words in column names
2021-10-29 18:19:35 +02:00
Thomas Landauer 276a0f55ee Removing paragraph on consts (#9158)
IMO, this is better shown by example, so I added it there.
2021-10-29 14:21:37 +02:00
Thomas Landauer dbaf99f3d9 Update events.rst 2021-10-29 01:17:32 +02:00
Thomas Landauer 97411f5567 Merging Lifecycle Callbacks code samples for PHP + XML + YAML
IMO, the text I deleted just repeated things that are obvious in the example anyway.
2021-10-29 01:12:02 +02:00
Chase Noel 641330baa6 Add doctrine/dbal to project composer.json (#9152)
As discussed in https://github.com/doctrine/orm/issues/9078 when entities utilize data mappings which are provided by the dbal lib it is expected behavior that users will explicitly define their dependency on the package.

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-10-28 23:42:05 +02:00
Thomas Landauer 35e680cd3f Fixing links in overview table (#9151)
I got them wrong in https://github.com/doctrine/orm/pull/9131 ;-)
2021-10-28 21:29:47 +02:00
Javier Spagnoletti 705d88eaba Add XSD "orm:columntoken" type in order to support reserved words in column names 2021-10-28 14:00:39 -03:00
Paul Waring 3271d8f6e2 Fix markup for variable names (#9150)
Three references to `$isDevMode` were marked up with a single backtick, however two backticks are required in order for the variable name to be highlighted correctly (c.f. `ArrayCache`).
2021-10-26 10:59:31 +00:00
Thomas Landauer 3622381f8c Overview table for events: Jump links (#9131)
* Overview table for events: Jump links

* Update events.rst
2021-10-25 22:34:36 +02:00
wickedOne f2729b0610 Return 0 when there's no metadata to process (#9147) 2021-10-23 09:43:40 +00:00
chapterjason cd44547573 Remove old use statements (#9146) 2021-10-23 11:32:44 +02:00
Grégoire Paris 81d472f6f9 Merge pull request #9139 from greg0ire/upgrade-workflows
Upgrade workflows to 1.1.1
2021-10-21 19:57:02 +02:00
Grégoire Paris d458968cee Upgrade workflows to 1.1.1
That version fixes a bug with the release workflow. Releasing is not
possible unless we do that upgrade.
2021-10-21 19:55:57 +02:00
Christophe Coevoet 5eb01da0a0 Fix the upgrade guide for 2.8 changes (#9138) 2021-10-21 16:44:42 +02:00
Grégoire Paris 5aaf361139 Merge pull request #9136 from greg0ire/revert-bc-break
Revert "Removing all the occurence of any"
2021-10-21 08:49:18 +02:00
Alexander M. Turek 6a8dcbc392 Regenerate Psalm baseline (#9135) 2021-10-20 23:30:57 +02:00
Grégoire Paris 12babcc1c2 Revert "Removing all the occurence of any"
This reverts commit 84afd6c937, because it
is a BC-break that seems to affect more people than we originally
thought it would.
2021-10-20 23:12:01 +02:00
Thomas Landauer 416aa1d2d7 Explaining the two major ways to register an event v2 (#9128)
Co-authored-by: Javier Spagnoletti <phansys@gmail.com>
2021-10-16 11:45:10 +02:00
Grégoire Paris 8e16bb4ddc Merge pull request #9126 from greg0ire/explicitly-pass-secrets
Explicitly pass secrets
2021-10-14 23:45:30 +02:00
Grégoire Paris e1dee439bb Explicitly pass secrets
Secrets are sensitive and not passed implicitly.
2021-10-14 23:35:29 +02:00
Thomas Landauer e313d012ae Overview table for events (#9039)
* Overview table for events

Better late than never - finally delivering what I announced at https://github.com/doctrine/orm/pull/8435#issuecomment-769940427 :-)

* Update events.rst

* Update events.rst

* Adding "Lifecycle Callback" column

* Update events.rst
2021-10-14 10:58:07 +02:00
Javier Spagnoletti dede619b9e Add "@method" annotation for wrapInTransaction() method at EntityManagerInterface (#9091) 2021-10-13 20:18:50 +02:00
Grégoire Paris 142cfb39fc Merge pull request #9114 from greg0ire/try-out-reusable-workflows
Directly reference upstream CS workflow
2021-10-11 21:00:41 +02:00
Alexander M. Turek 53d41a456a PHP CodeSniffer 3.6.1 (#9115) 2021-10-11 12:05:46 +02:00
Grégoire Paris 95b34ca940 Directly reference some upstream workflows 2021-10-10 21:08:57 +02:00
Paul Capron 3eaf76eebd Fix typo & minor issues in dql-custom-walkers.rst (#9113) 2021-10-09 23:29:38 +02:00
Grégoire Paris 5c12d36be3 Merge pull request #9107 from BackEndTea/patch-1
Remove the twitter #doctrine2 hashtag refference
2021-10-07 22:35:44 +02:00
Grégoire Paris 1ee68eb318 Merge pull request #9098 from ajgarlag/bugfix-indexed-iterable
Honor INDEX BY construct in Query::toIterable
2021-10-07 22:34:54 +02:00
orklah 705c7f0a4b [Psalm] always true/false conditions (#9108) 2021-10-07 20:21:58 +02:00
Gert de Pagter 8c5e49efc0 Remove the twitter #doctrine2 hashtag refference
Looking at twitter, the hashtag its hardly used. There was 1 question posted in the last year, and it went unanswered.

The `2` part has mostly been dropped everywhere, and orm is now just refered to doctrine orm instead of doctrine2
2021-10-07 16:12:06 +02:00
Antonio J. García Lagar 483e09cf1c Fix Query::toIterable to honor INDEX BY construct 2021-10-07 13:02:22 +02:00
Benjamin Morel bbb68d0072 Fix SchemaValidator with abstract child class in discriminator map (#9096) 2021-10-06 22:35:51 +02:00
Knallcharge f346379c7b Add integer cast in setFirstResult methods of Query and QueryBuilder (#9090) 2021-10-05 15:04:30 +02:00
Michael Telgmann b1c31e1aac Add integer cast in setMaxResults methods of Query and QueryBuilder (#9079) 2021-10-04 23:00:38 +02:00
Grégoire Paris 02b6f9c335 Merge pull request #9084 from annechko/patch-1
Update phpdoc comment - association-mapping.rst
2021-10-04 21:59:30 +02:00
Anna Borzenko d14d9919c7 Update phpdoc comment 2021-10-04 21:50:03 +02:00
Grégoire Paris bd79e3d383 Merge pull request #9068 from greg0ire/update-branch-metadata
Reflect latest minor release in metadata
2021-10-03 22:48:37 +02:00
Grégoire Paris 10f72417c9 Reflect latest minor release in metadata 2021-10-03 21:12:59 +02:00
Grégoire Paris 87ad869a8a Merge pull request #9067 from greg0ire/use-latest-laminas-release
Use latest laminas release
2021-10-03 21:08:55 +02:00
Grégoire Paris bc4659b73c Revert "Pin laminas/automatic-releases to 1.11.1"
This reverts commit e800f90d7c.
2021-10-03 20:56:35 +02:00
Grégoire Paris 4eab6536c3 Revert "Try using docker image directly"
This reverts commit ddcea63d0f.
2021-10-03 20:56:27 +02:00
Grégoire Paris 1571c8a781 Revert "Explicitly disallow workflows for tags"
This reverts commit bbe4022566.
2021-10-03 20:56:12 +02:00
Grégoire Paris 20a65cbe32 Revert "Use org admin token"
This reverts commit e8a221d227.
2021-10-03 20:55:17 +02:00
51 changed files with 1159 additions and 527 deletions
+12 -6
View File
@@ -12,21 +12,27 @@
"upcoming": true
},
{
"name": "2.10",
"branchName": "2.10.x",
"slug": "2.10",
"name": "2.11",
"branchName": "2.11.x",
"slug": "2.11",
"upcoming": true
},
{
"name": "2.9",
"branchName": "2.9.x",
"slug": "2.9",
"name": "2.10",
"branchName": "2.10.x",
"slug": "2.10",
"current": true,
"aliases": [
"current",
"stable"
]
},
{
"name": "2.9",
"branchName": "2.9.x",
"slug": "2.9",
"maintained": false
},
{
"name": "2.8",
"branchName": "2.8.x",
+3 -27
View File
@@ -10,30 +10,6 @@ on:
jobs:
coding-standards:
name: "Coding Standards"
runs-on: "ubuntu-20.04"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: "cs2pr"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
with:
dependency-versions: "highest"
# https://github.com/doctrine/.github/issues/3
- name: "Run PHP_CodeSniffer"
run: "vendor/bin/phpcs -q --no-colors --report=checkstyle | cs2pr"
uses: "doctrine/.github/.github/workflows/coding-standards.yml@1.1.1"
with:
php-version: "7.4"
@@ -4,13 +4,9 @@ on:
pull_request:
branches:
- "*.x"
tag-ignore:
- "*"
push:
branches:
- "*.x"
tag-ignore:
- "*"
env:
fail-fast: true
@@ -7,46 +7,10 @@ on:
jobs:
release:
name: "Git tag, release & create merge-up PR"
runs-on: "ubuntu-20.04"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
- name: "Release"
# revert to v1 when
# https://github.com/laminas/automatic-releases/issues/166 is fixed
uses: "docker://ghcr.io/laminas/automatic-releases:1.11.1"
with:
args: "laminas:automatic-releases:release"
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 }}
"SHELL_VERBOSITY": "3"
- name: "Create Merge-Up Pull Request"
# revert to v1 when
# https://github.com/laminas/automatic-releases/issues/166 is fixed
uses: "docker://ghcr.io/laminas/automatic-releases:1.11.1"
with:
args: "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 new milestones"
# revert to v1 when
# https://github.com/laminas/automatic-releases/issues/166 is fixed
uses: "docker://ghcr.io/laminas/automatic-releases:1.11.1"
with:
args: "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 }}
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@1.1.1"
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
ORGANIZATION_ADMIN_TOKEN: ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
SIGNING_SECRET_KEY: ${{ secrets.SIGNING_SECRET_KEY }}
+7 -7
View File
@@ -1,7 +1,7 @@
| [3.0.x][3.0] | [2.10.x][2.10] | [2.9.x][2.9] |
| [3.0.x][3.0] | [2.11.x][2.11] | [2.10.x][2.10] |
|:----------------:|:----------------:|:----------:|
| [![Build status][3.0 image]][3.0] | [![Build status][2.10 image]][2.10] | [![Build status][2.9 image]][2.9] |
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.10 coverage image]][2.10 coverage] | [![Coverage Status][2.9 coverage image]][2.9 coverage] |
| [![Build status][3.0 image]][3.0] | [![Build status][2.11 image]][2.11] | [![Build status][2.10 image]][2.10] |
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.11 coverage image]][2.11 coverage] | [![Coverage Status][2.10 coverage image]][2.10 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
@@ -20,11 +20,11 @@ without requiring unnecessary code duplication.
[3.0]: https://github.com/doctrine/orm/tree/3.0.x
[3.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.0.x/graph/badge.svg
[3.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.0.x
[2.9 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.9.x
[2.9]: https://github.com/doctrine/orm/tree/2.9.x
[2.9 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.9.x/graph/badge.svg
[2.9 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.9.x
[2.10 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.10.x
[2.10]: https://github.com/doctrine/orm/tree/2.10.x
[2.10 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.10.x/graph/badge.svg
[2.10 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.10.x
[2.11 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.11.x
[2.11]: https://github.com/doctrine/orm/tree/2.11.x
[2.11 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.11.x/graph/badge.svg
[2.11 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.11.x
+10 -7
View File
@@ -1,5 +1,12 @@
# Upgrade to 2.10
## BC Break: `UnitOfWork` now relies on SPL object IDs, not hashes
When calling the following methods, you are now supposed to use the result of
`spl_object_id()`, and not `spl_object_hash()`:
- `UnitOfWork::clearEntityChangeSet()`
- `UnitOfWork::setOriginalEntityProperty()`
## BC Break: Removed `TABLE` id generator strategy
The implementation was unfinished for 14 years.
@@ -9,10 +16,6 @@ It is now deprecated to rely on:
- `Doctrine\ORM\Mapping\ClassMetadata::$tableGeneratorDefinition`;
- or `Doctrine\ORM\Mapping\ClassMetadata::isIdGeneratorTable()`.
## BC Break: Removed possibility to extend the doctrine mapping xml schema with anything
If you want to extend it now you have to provide your own validation schema.
## New method `Doctrine\ORM\EntityManagerInterface#wrapInTransaction($func)`
Works the same as `Doctrine\ORM\EntityManagerInterface#transactional()` but returns any value returned from `$func` closure rather than just _non-empty value returned from the closure or true_.
@@ -108,10 +111,10 @@ now always cleared regardless of the cache adapter being used.
Method `Doctrine\ORM\UnitOfWork#commit()` can throw an OptimisticLockException when a commit silently fails and returns false
since `Doctrine\DBAL\Connection#commit()` signature changed from returning void to boolean
## Deprecated: `Doctrine\ORM\AbstractQuery#iterator()`
## Deprecated: `Doctrine\ORM\AbstractQuery#iterate()`
The method `Doctrine\ORM\AbstractQuery#iterator()` is deprecated in favor of `Doctrine\ORM\AbstractQuery#toIterable()`.
Note that `toIterable()` yields results of the query, unlike `iterator()` which yielded each result wrapped into an array.
The method `Doctrine\ORM\AbstractQuery#iterate()` is deprecated in favor of `Doctrine\ORM\AbstractQuery#toIterable()`.
Note that `toIterable()` yields results of the query, unlike `iterate()` which yielded each result wrapped into an array.
# Upgrade to 2.7
+3 -3
View File
@@ -39,12 +39,12 @@
"doctrine/annotations": "^1.13",
"doctrine/coding-standard": "^9.0",
"phpbench/phpbench": "^0.16.10 || ^1.0",
"phpstan/phpstan": "0.12.99",
"phpstan/phpstan": "1.2.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
"squizlabs/php_codesniffer": "3.6.0",
"squizlabs/php_codesniffer": "3.6.1",
"symfony/cache": "^4.4 || ^5.2",
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
"vimeo/psalm": "4.10.0"
"vimeo/psalm": "4.13.1"
},
"conflict": {
"doctrine/annotations": "<1.13 || >= 2.0"
+5 -5
View File
@@ -33,8 +33,8 @@ the DQL parser:
is only ever one of them. We implemented the default SqlWalker
implementation for it.
- A tree walker. There can be many tree walkers, they cannot
generate the sql, however they can modify the AST before its
rendered to sql.
generate the SQL, however they can modify the AST before its
rendered to SQL.
Now this is all awfully technical, so let me come to some use-cases
fast to keep you motivated. Using walker implementation you can for
@@ -50,7 +50,7 @@ example:
- Modify the Output walker to pretty print the SQL for debugging
purposes.
In this cookbook-entry I will show examples on the first two
In this cookbook-entry I will show examples of the first two
points. There are probably much more use-cases.
Generic count query for pagination
@@ -64,7 +64,7 @@ like:
SELECT p, c, a FROM BlogPost p JOIN p.category c JOIN p.author a WHERE ...
Now in this query the blog post is the root entity, meaning its the
Now in this query the blog post is the root entity, meaning it's the
one that is hydrated directly from the query and returned as an
array of blog posts. In contrast the comment and author are loaded
for deeper use in the object tree.
@@ -79,7 +79,7 @@ query for pagination would look like:
SELECT count(DISTINCT p.id) FROM BlogPost p JOIN p.category c JOIN p.author a WHERE ...
Now you could go and write each of these queries by hand, or you
can use a tree walker to modify the AST for you. Lets see how the
can use a tree walker to modify the AST for you. Let's see how the
API would look for this use-case:
.. code-block:: php
-1
View File
@@ -16,7 +16,6 @@ Doctrine ORM don't panic. You can get help from different sources:
- The `Doctrine Mailing List <https://groups.google.com/group/doctrine-user>`_
- Slack chat room `#orm <https://www.doctrine-project.org/slack>`_
- Report a bug on `GitHub <https://github.com/doctrine/orm/issues>`_.
- On `Twitter <https://twitter.com/search/%23doctrine2>`_ with ``#doctrine2``
- On `StackOverflow <https://stackoverflow.com/questions/tagged/doctrine-orm>`_
If you need more structure over the different topics you can browse the :doc:`table
+2
View File
@@ -184,6 +184,8 @@ in well defined units of work. Work with your objects and modify
them as usual and when you're done call ``EntityManager#flush()``
to make your changes persistent.
.. _unit-of-work:
The Unit of Work
~~~~~~~~~~~~~~~~
+1 -1
View File
@@ -430,7 +430,7 @@ The following example sets up such a unidirectional one-to-many association:
// ...
/**
* Many User have Many Phonenumbers.
* Many Users have Many Phonenumbers.
* @ManyToMany(targetEntity="Phonenumber")
* @JoinTable(name="users_phonenumbers",
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
+3 -3
View File
@@ -85,9 +85,9 @@ Or if you prefer YAML:
Inside the ``Setup`` methods several assumptions are made:
- If `$isDevMode` is true caching is done in memory with the ``ArrayCache``. Proxy objects are recreated on every request.
- If `$isDevMode` is false, check for Caches in the order APC, Xcache, Memcache (127.0.0.1:11211), Redis (127.0.0.1:6379) unless `$cache` is passed as fourth argument.
- If `$isDevMode` is false, set then proxy classes have to be explicitly created through the command line.
- If ``$isDevMode`` is true caching is done in memory with the ``ArrayCache``. Proxy objects are recreated on every request.
- If ``$isDevMode`` is false, check for Caches in the order APC, Xcache, Memcache (127.0.0.1:11211), Redis (127.0.0.1:6379) unless `$cache` is passed as fourth argument.
- If ``$isDevMode`` is false, set then proxy classes have to be explicitly created through the command line.
- If third argument `$proxyDir` is not set, use the systems temporary directory.
If you want to configure Doctrine in more detail, take a look at the :doc:`Advanced Configuration <reference/advanced-configuration>` section.
+173 -129
View File
@@ -121,6 +121,53 @@ Now you can test the ``$eventSubscriber`` instance to see if the
echo 'pre foo invoked!';
}
Registering Events
~~~~~~~~~~~~~~~~~~
There are two ways to register an event:
* *All events* can be registered by calling ``$eventManager->addEventListener()``
or ``eventManager->addEventSubscriber()``, see
:ref:`Listening and subscribing to Lifecycle Events<listening-and-subscribing-to-lifecycle-events>`
* *Lifecycle Callbacks* can also be registered in the entity mapping (annotation, attribute, etc.),
see :ref:`Lifecycle Callbacks<lifecycle-callbacks>`
Events Overview
---------------
+-----------------------------------------------------------------+-----------------------+-----------+
| Event | Dispatched by | Lifecycle |
| | | Callback |
+=================================================================+=======================+===========+
| :ref:`preRemove<reference-events-pre-remove>` | ``$em->remove()`` | Yes |
+-----------------------------------------------------------------+-----------------------+-----------+
| :ref:`postRemove<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes |
+-----------------------------------------------------------------+-----------------------+-----------+
| :ref:`prePersist<reference-events-pre-persist>` | ``$em->persist()`` | Yes |
| | on *initial* persist | |
+-----------------------------------------------------------------+-----------------------+-----------+
| :ref:`postPersist<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes |
+-----------------------------------------------------------------+-----------------------+-----------+
| :ref:`preUpdate<reference-events-pre-update>` | ``$em->flush()`` | Yes |
+-----------------------------------------------------------------+-----------------------+-----------+
| :ref:`postUpdate<reference-events-post-update-remove-persist>` | ``$em->flush()`` | Yes |
+-----------------------------------------------------------------+-----------------------+-----------+
| :ref:`postLoad<reference-events-post-load>` | Loading from database | Yes |
+-----------------------------------------------------------------+-----------------------+-----------+
| :ref:`loadClassMetadata<reference-events-load-class-metadata>` | Loading of mapping | No |
| | metadata | |
+-----------------------------------------------------------------+-----------------------+-----------+
| ``onClassMetadataNotFound`` | ``MappingException`` | No |
+-----------------------------------------------------------------+-----------------------+-----------+
| :ref:`preFlush<reference-events-pre-flush>` | ``$em->flush()`` | Yes |
+-----------------------------------------------------------------+-----------------------+-----------+
| :ref:`onFlush<reference-events-on-flush>` | ``$em->flush()`` | No |
+-----------------------------------------------------------------+-----------------------+-----------+
| :ref:`postFlush<reference-events-post-flush>` | ``$em->flush()`` | No |
+-----------------------------------------------------------------+-----------------------+-----------+
| ``onClear`` | ``$em->clear()`` | No |
+-----------------------------------------------------------------+-----------------------+-----------+
Naming convention
~~~~~~~~~~~~~~~~~
@@ -208,15 +255,6 @@ events during the life-time of their registered entities.
cascade remove relations. In this case, you should load yourself the proxy in
the associated pre event.
You can access the Event constants from the ``Events`` class in the
ORM package.
.. code-block:: php
<?php
use Doctrine\ORM\Events;
echo Events::preUpdate;
These can be hooked into by two different types of event
listeners:
@@ -237,6 +275,7 @@ The ``EventArgs`` instance received by the listener gives access to the entity,
:ref:`reference-events-implementing-listeners` section very carefully
to understand which operations are allowed in which lifecycle event.
.. _lifecycle-callbacks:
Lifecycle Callbacks
-------------------
@@ -250,135 +289,104 @@ specific to a particular entity class's lifecycle.
.. note::
Note that Licecycle Callbacks are not supported for Embeddables.
Lifecycle Callbacks are not supported for :doc:`Embeddables </tutorials/embeddables>`.
.. code-block:: php
.. configuration-block::
<?php
.. code-block:: attribute
/** @Entity @HasLifecycleCallbacks */
class User
{
// ...
<?php
/**
* @Column(type="string", length=255)
* #[Entity]
* #[HasLifecycleCallbacks]
*/
public $value;
/** @Column(name="created_at", type="string", length=255) */
private $createdAt;
/** @PrePersist */
public function doStuffOnPrePersist()
{
$this->createdAt = date('Y-m-d H:i:s');
}
/** @PrePersist */
public function doOtherStuffOnPrePersist()
{
$this->value = 'changed from prePersist callback!';
}
/** @PostPersist */
public function doStuffOnPostPersist()
{
$this->value = 'changed from postPersist callback!';
}
/** @PostLoad */
public function doStuffOnPostLoad()
{
$this->value = 'changed from postLoad callback!';
}
/** @PreUpdate */
public function doStuffOnPreUpdate()
{
$this->value = 'changed from preUpdate callback!';
}
}
Note that the methods set as lifecycle callbacks need to be public and,
when using these annotations, you have to apply the
``@HasLifecycleCallbacks`` marker annotation on the entity class.
If you want to register lifecycle callbacks from YAML or XML you
can do it with the following.
.. code-block:: yaml
User:
type: entity
fields:
# ...
name:
type: string(50)
lifecycleCallbacks:
prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersist ]
postPersist: [ doStuffOnPostPersist ]
In YAML the ``key`` of the lifecycleCallbacks entry is the event that you
are triggering on and the value is the method (or methods) to call. The allowed
event types are the ones listed in the previous Lifecycle Events section.
XML would look something like this:
.. code-block:: xml
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="User">
<lifecycle-callbacks>
<lifecycle-callback type="prePersist" method="doStuffOnPrePersist"/>
<lifecycle-callback type="postPersist" method="doStuffOnPostPersist"/>
</lifecycle-callbacks>
</entity>
</doctrine-mapping>
In XML the ``type`` of the lifecycle-callback entry is the event that you
are triggering on and the ``method`` is the method to call. The allowed event
types are the ones listed in the previous Lifecycle Events section.
When using YAML or XML you need to remember to create public methods to match the
callback names you defined. E.g. in these examples ``doStuffOnPrePersist()``,
``doOtherStuffOnPrePersist()`` and ``doStuffOnPostPersist()`` methods need to be
defined on your ``User`` model.
.. code-block:: php
<?php
// ...
class User
{
// ...
public function doStuffOnPrePersist()
class User
{
// ...
}
public function doOtherStuffOnPrePersist()
#[Column(type: 'string', length: 255)]
public $value;
#[PrePersist]
public function doStuffOnPrePersist()
{
$this->createdAt = date('Y-m-d H:i:s');
}
#[PrePersist]
public function doOtherStuffOnPrePersist()
{
$this->value = 'changed from prePersist callback!';
}
#[PostLoad]
public function doStuffOnPostLoad()
{
$this->value = 'changed from postLoad callback!';
}
}
.. code-block:: annotation
<?php
/**
* @Entity
* @HasLifecycleCallbacks
*/
class User
{
// ...
}
public function doStuffOnPostPersist()
{
// ...
}
}
/** @Column(type="string", length=255) */
public $value;
/** @PrePersist */
public function doStuffOnPrePersist()
{
$this->createdAt = date('Y-m-d H:i:s');
}
/** @PrePersist */
public function doOtherStuffOnPrePersist()
{
$this->value = 'changed from prePersist callback!';
}
/** @PostLoad */
public function doStuffOnPostLoad()
{
$this->value = 'changed from postLoad callback!';
}
}
.. code-block:: xml
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://doctrine-project.org/schemas/orm/doctrine-mapping
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="User">
<!-- ... -->
<lifecycle-callbacks>
<lifecycle-callback type="prePersist" method="doStuffOnPrePersist"/>
<lifecycle-callback type="prePersist" method="doOtherStuffOnPrePersist"/>
<lifecycle-callback type="postLoad" method="doStuffOnPostLoad"/>
</lifecycle-callbacks>
</entity>
</doctrine-mapping>
.. code-block:: yaml
User:
type: entity
fields:
# ...
value:
type: string(255)
lifecycleCallbacks:
prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersist ]
postLoad: [ doStuffOnPostLoad ]
Lifecycle Callbacks Event Argument
----------------------------------
@@ -403,6 +411,8 @@ With the additional argument you have access to the
}
}
.. _listening-and-subscribing-to-lifecycle-events:
Listening and subscribing to Lifecycle Events
---------------------------------------------
@@ -413,7 +423,7 @@ behaviors across different entity classes.
Note that they require much more detailed knowledge about the inner
workings of the ``EntityManager`` and ``UnitOfWork`` classes. Please
read the :ref:`reference-events-implementing-listeners` section
read the :ref:`Implementing Event Listeners<reference-events-implementing-listeners>` section
carefully if you are trying to write your own listener.
For event subscribers, there are no surprises. They declare the
@@ -482,8 +492,10 @@ EventManager that is passed to the EntityManager factory:
.. code-block:: php
<?php
use Doctrine\ORM\Events;
$eventManager = new EventManager();
$eventManager->addEventListener(array(Events::preUpdate), new MyEventListener());
$eventManager->addEventListener([Events::preUpdate], new MyEventListener());
$eventManager->addEventSubscriber(new MyEventSubscriber());
$entityManager = EntityManager::create($dbOpts, $config, $eventManager);
@@ -494,7 +506,9 @@ EntityManager was created:
.. code-block:: php
<?php
$entityManager->getEventManager()->addEventListener(array(Events::preUpdate), new MyEventListener());
use Doctrine\ORM\Events;
$entityManager->getEventManager()->addEventListener([Events::preUpdate], new MyEventListener());
$entityManager->getEventManager()->addEventSubscriber(new MyEventSubscriber());
.. _reference-events-implementing-listeners:
@@ -514,6 +528,8 @@ 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.
.. _reference-events-pre-persist:
prePersist
~~~~~~~~~~
@@ -539,6 +555,8 @@ The following restrictions apply to ``prePersist``:
- Doctrine will not recognize changes made to relations in a prePersist
event. This includes modifications to
collections such as additions, removals or replacement.
.. _reference-events-pre-remove:
preRemove
~~~~~~~~~
@@ -551,6 +569,8 @@ There are no restrictions to what methods can be called inside the
``preRemove`` event, except when the remove method itself was
called during a flush operation.
.. _reference-events-pre-flush:
preFlush
~~~~~~~~
@@ -573,6 +593,8 @@ result in infinite loop.
}
}
.. _reference-events-on-flush:
onFlush
~~~~~~~
@@ -636,6 +658,8 @@ The following restrictions apply to the onFlush event:
affected entity. This can be done by calling
``$unitOfWork->recomputeSingleEntityChangeSet($classMetadata, $entity)``.
.. _reference-events-post-flush:
postFlush
~~~~~~~~~
@@ -656,6 +680,8 @@ postFlush
}
}
.. _reference-events-pre-update:
preUpdate
~~~~~~~~~
@@ -740,6 +766,8 @@ Restrictions for this event:
API are strongly discouraged and don't work as expected outside the
flush operation.
.. _reference-events-post-update-remove-persist:
postUpdate, postRemove, postPersist
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -749,6 +777,8 @@ database, but you can use these events to alter non-persistable items,
like non-mapped fields, logging or even associated classes that are
not directly mapped by Doctrine.
.. _reference-events-post-load:
postLoad
~~~~~~~~
@@ -765,7 +795,19 @@ An entity listener is a lifecycle listener class used for an entity.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
namespace MyProject\Entity;
use App\EventListener\UserListener;
#[Entity]
#[EntityListeners([UserListener::class])]
class User
{
// ....
}
.. code-block:: annotation
<?php
namespace MyProject\Entity;
@@ -961,6 +1003,8 @@ Implementing your own resolver :
$configurations->setEntityListenerResolver(new MyEntityListenerResolver);
EntityManager::create(.., $configurations, ..);
.. _reference-events-load-class-metadata:
Load ClassMetadata Event
------------------------
@@ -40,7 +40,7 @@ easily using a combination of ``count`` and ``slice``.
``removeElement`` directly issued DELETE queries to the database from
version 2.4.0 to 2.7.0. This circumvents the flush operation and might run
outside a transactional boundary if you don't create one yourself. We
consider this a critical bug in the assumptio of how the ORM works and
consider this a critical bug in the assumption of how the ORM works and
reverted ``removeElement`` EXTRA_LAZY behavior in 2.7.1.
+12 -3
View File
@@ -81,7 +81,8 @@ that directory with the following contents:
{
"require": {
"doctrine/orm": "^2.6.2",
"doctrine/orm": "^2.10.2",
"doctrine/dbal": "^3.1.1",
"symfony/yaml": "2.*",
"symfony/cache": "^5.3"
},
@@ -112,6 +113,14 @@ Add the following directories:
.. note::
The YAML driver is deprecated and will be removed in version 3.0.
It is strongly recommended to switch to one of the other mappings.
.. note::
It is strongly recommended that you require ``doctrine/dbal`` in your
``composer.json`` as well, because using the ORM means mapping objects
and their fields to database tables and their columns, and that
requires mentioning so-called types that are defined in ``doctrine/dbal``
in your application. Having an explicit requirement means you control
when the upgrade to the next major version happens, so that you can
do the necessary changes in your application beforehand.
Obtaining the EntityManager
---------------------------
@@ -642,7 +651,7 @@ Let's continue by creating a script to display the name of a product based on it
echo sprintf("-%s\n", $product->getName());
Next we'll update a product's name, given its id. This simple example will
help demonstrate Doctrine's implementation of the UnitOfWork pattern. Doctrine
help demonstrate Doctrine's implementation of the :ref:`UnitOfWork pattern <unit-of-work>`. Doctrine
keeps track of all the entities that were retrieved from the Entity Manager,
and can detect when any of those entities' properties have been modified.
As a result, rather than needing to call ``persist($entity)`` for each individual
@@ -1334,7 +1343,7 @@ call this script as follows:
php create_bug.php 1 1 1
See how simple it is to relate a Bug, Reporter, Engineer and Products?
Also recall that thanks to the UnitOfWork pattern, Doctrine will detect
Also recall that thanks to the :ref:`UnitOfWork pattern <unit-of-work>`, Doctrine will detect
these relations and update all of the modified entities in the database
automatically when ``flush()`` is called.
+84 -3
View File
@@ -18,13 +18,17 @@
<xs:element name="mapped-superclass" type="orm:mapped-superclass" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="entity" type="orm:entity" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="embeddable" type="orm:embeddable" minOccurs="0" maxOccurs="unbounded" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
</xs:element>
<xs:complexType name="emptyType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="cascade-type">
@@ -35,7 +39,9 @@
<xs:element name="cascade-remove" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-refresh" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-detach" type="orm:emptyType" minOccurs="0"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:simpleType name="lifecycle-callback-type">
@@ -61,15 +67,19 @@
<xs:complexType name="lifecycle-callback">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="type" type="orm:lifecycle-callback-type" use="required" />
<xs:attribute name="method" type="xs:NMTOKEN" use="required" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="lifecycle-callbacks">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="lifecycle-callback" type="orm:lifecycle-callback" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="named-query">
@@ -88,6 +98,7 @@
<xs:complexType name="named-native-query">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="query" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="result-class" type="orm:fqcn" />
@@ -97,12 +108,14 @@
<xs:complexType name="named-native-queries">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="named-native-query" type="orm:named-native-query" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="entity-listener">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="lifecycle-callback" type="orm:lifecycle-callback" minOccurs="0" maxOccurs="unbounded"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="class" type="orm:fqcn"/>
</xs:complexType>
@@ -135,7 +148,9 @@
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="entity-result" type="orm:entity-result"/>
<xs:element name="column-result" type="orm:column-result"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
@@ -173,6 +188,7 @@
<xs:element name="many-to-many" type="orm:many-to-many" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="association-overrides" type="orm:association-overrides" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="attribute-overrides" type="orm:attribute-overrides" minOccurs="0" maxOccurs="unbounded" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="table" type="orm:tablename" />
@@ -181,6 +197,7 @@
<xs:attribute name="inheritance-type" type="orm:inheritance-type"/>
<xs:attribute name="change-tracking-policy" type="orm:change-tracking-policy" />
<xs:attribute name="read-only" type="xs:boolean" default="false" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:simpleType name="tablename" id="tablename">
@@ -193,21 +210,27 @@
<xs:complexType name="option" mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="option" type="orm:option"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="options">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="option" type="orm:option" minOccurs="0" maxOccurs="unbounded"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="mapped-superclass" >
<xs:complexContent>
<xs:extension base="orm:entity">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
@@ -216,6 +239,7 @@
<xs:complexContent>
<xs:extension base="orm:entity">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
@@ -267,10 +291,11 @@
<xs:complexType name="field">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
<xs:attribute name="column" type="xs:NMTOKEN" />
<xs:attribute name="column" type="orm:columntoken" />
<xs:attribute name="length" type="xs:NMTOKEN" />
<xs:attribute name="unique" type="xs:boolean" default="false" />
<xs:attribute name="nullable" type="xs:boolean" default="false" />
@@ -278,6 +303,7 @@
<xs:attribute name="column-definition" type="xs:string" />
<xs:attribute name="precision" type="xs:integer" use="optional" />
<xs:attribute name="scale" type="xs:integer" use="optional" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="embedded">
@@ -292,62 +318,78 @@
<xs:complexType name="discriminator-column">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="type" type="xs:NMTOKEN"/>
<xs:attribute name="field-name" type="xs:NMTOKEN" />
<xs:attribute name="length" type="xs:NMTOKEN" />
<xs:attribute name="column-definition" type="xs:string" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="unique-constraint">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="optional"/>
<xs:attribute name="columns" type="xs:string" use="optional"/>
<xs:attribute name="fields" type="xs:string" use="optional"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="unique-constraints">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="unique-constraint" type="orm:unique-constraint" minOccurs="1" maxOccurs="unbounded"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="index">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="optional"/>
<xs:attribute name="columns" type="xs:string" use="required"/>
<xs:attribute name="fields" type="xs:string" use="optional"/>
<xs:attribute name="flags" type="xs:string" use="optional"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="indexes">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="index" type="orm:index" minOccurs="1" maxOccurs="unbounded"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="discriminator-mapping">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="value" type="xs:NMTOKEN" use="required"/>
<xs:attribute name="class" type="orm:fqcn" use="required"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="discriminator-map">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="discriminator-mapping" type="orm:discriminator-mapping" minOccurs="1" maxOccurs="unbounded"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="generator">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="strategy" type="orm:generator-strategy" use="optional" default="AUTO" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="id">
@@ -356,25 +398,30 @@
<xs:element name="sequence-generator" type="orm:sequence-generator" minOccurs="0" maxOccurs="1" />
<xs:element name="custom-id-generator" type="orm:custom-id-generator" minOccurs="0" maxOccurs="1" />
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="type" type="xs:NMTOKEN" />
<xs:attribute name="column" type="xs:NMTOKEN" />
<xs:attribute name="column" type="orm:columntoken" />
<xs:attribute name="length" type="xs:NMTOKEN" />
<xs:attribute name="association-key" type="xs:boolean" default="false" />
<xs:attribute name="column-definition" type="xs:string" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="sequence-generator">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="sequence-name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="allocation-size" type="xs:integer" use="optional" default="1" />
<xs:attribute name="initial-value" type="xs:integer" use="optional" default="1" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="custom-id-generator">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="class" type="orm:fqcn" use="required" />
</xs:complexType>
@@ -389,11 +436,14 @@
<xs:complexType name="inverse-join-columns">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="join-column">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="optional" />
<xs:attribute name="referenced-column-name" type="xs:NMTOKEN" use="optional" default="id" />
@@ -401,34 +451,43 @@
<xs:attribute name="nullable" type="xs:boolean" default="true" />
<xs:attribute name="on-delete" type="orm:fk-action" />
<xs:attribute name="column-definition" type="xs:string" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="join-columns">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="join-column" type="orm:join-column" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="join-table">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="join-columns" type="orm:join-columns" />
<xs:element name="inverse-join-columns" type="orm:join-columns" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="schema" type="xs:NMTOKEN" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="order-by">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="order-by-field" type="orm:order-by-field" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="order-by-field">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="direction" type="orm:order-by-direction" default="ASC" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:simpleType name="order-by-direction">
@@ -438,12 +497,19 @@
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="columntoken" id="columntoken">
<xs:restriction base="xs:token">
<xs:pattern value="[-._:A-Za-z0-9`]+" id="columntoken.pattern"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="many-to-many">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="cache" type="orm:cache" minOccurs="0" maxOccurs="1"/>
<xs:element name="cascade" type="orm:cascade-type" minOccurs="0" />
<xs:element name="join-table" type="orm:join-table" minOccurs="0" />
<xs:element name="order-by" type="orm:order-by" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="target-entity" type="xs:string" use="required" />
@@ -452,6 +518,7 @@
<xs:attribute name="index-by" type="xs:NMTOKEN" />
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="one-to-many">
@@ -459,6 +526,7 @@
<xs:element name="cache" type="orm:cache" minOccurs="0" maxOccurs="1"/>
<xs:element name="cascade" type="orm:cascade-type" minOccurs="0" />
<xs:element name="order-by" type="orm:order-by" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="target-entity" type="xs:string" use="required" />
@@ -466,6 +534,7 @@
<xs:attribute name="index-by" type="xs:NMTOKEN" />
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="many-to-one">
@@ -475,12 +544,15 @@
<xs:choice minOccurs="0" maxOccurs="1">
<xs:element name="join-column" type="orm:join-column"/>
<xs:element name="join-columns" type="orm:join-columns"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="target-entity" type="xs:string" />
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="one-to-one">
@@ -490,7 +562,9 @@
<xs:choice minOccurs="0" maxOccurs="1">
<xs:element name="join-column" type="orm:join-column"/>
<xs:element name="join-columns" type="orm:join-columns"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="target-entity" type="xs:string" />
@@ -498,11 +572,13 @@
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
<xs:attribute name="orphan-removal" type="xs:boolean" default="false" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="association-overrides">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="association-override" type="orm:association-override" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
</xs:complexType>
@@ -511,6 +587,7 @@
<xs:element name="join-table" type="orm:join-table" minOccurs="0" />
<xs:element name="join-columns" type="orm:join-columns" minOccurs="0" />
<xs:element name="inversed-by" type="orm:inversed-by-override" minOccurs="0" maxOccurs="1" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="fetch" type="orm:fetch-type" use="optional" />
@@ -523,12 +600,14 @@
<xs:complexType name="attribute-overrides">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="attribute-override" type="orm:attribute-override" minOccurs="1" maxOccurs="unbounded" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="attribute-override">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="field" type="orm:attribute-override-field" minOccurs="1" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
</xs:complexType>
@@ -536,9 +615,10 @@
<xs:complexType name="attribute-override-field">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
<xs:attribute name="column" type="xs:NMTOKEN" />
<xs:attribute name="column" type="orm:columntoken" />
<xs:attribute name="length" type="xs:NMTOKEN" />
<xs:attribute name="unique" type="xs:boolean" default="false" />
<xs:attribute name="nullable" type="xs:boolean" default="false" />
@@ -546,6 +626,7 @@
<xs:attribute name="column-definition" type="xs:string" />
<xs:attribute name="precision" type="xs:integer" use="optional" />
<xs:attribute name="scale" type="xs:integer" use="optional" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
</xs:schema>
+2 -1
View File
@@ -1253,7 +1253,8 @@ abstract class AbstractQuery
* Will return the configured id if it exists otherwise a hash will be
* automatically generated for you.
*
* @return array<string, string> ($key, $hash)
* @return string[] ($key, $hash)
* @psalm-return array{string, string} ($key, $hash)
*/
protected function getHydrationCacheId()
{
@@ -357,9 +357,7 @@ abstract class AbstractEntityPersister implements CachedEntityPersister
$cached = $queryCache->put($queryKey, $rsm, [$result]);
if ($this->cacheLogger) {
if ($result) {
$this->cacheLogger->queryCacheMiss($this->regionName, $queryKey);
}
$this->cacheLogger->queryCacheMiss($this->regionName, $queryKey);
if ($cached) {
$this->cacheLogger->queryCachePut($this->regionName, $queryKey);
@@ -5,9 +5,7 @@ declare(strict_types=1);
namespace Doctrine\ORM\Cache\Persister\Entity;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Cache\CacheException;
use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyEntity;
use Doctrine\ORM\Utility\StaticClassNameConverter;
/**
* Specific read-only region entity persister
+1 -2
View File
@@ -19,6 +19,7 @@ use Doctrine\Persistence\ObjectManager;
* EntityManager interface
*
* @method Mapping\ClassMetadataFactory getMetadataFactory()
* @method mixed wrapInTransaction(callable $func)
*/
interface EntityManagerInterface extends ObjectManager
{
@@ -329,11 +330,9 @@ interface EntityManagerInterface extends ObjectManager
* {@inheritDoc}
*
* @psalm-param string|class-string<T> $className
* @phpstan-param string $className
*
* @return Mapping\ClassMetadata
* @psalm-return Mapping\ClassMetadata<T>
* @phpstan-return Mapping\ClassMetadata<object>
*
* @psalm-template T of object
*/
@@ -142,7 +142,7 @@ abstract class AbstractHydrator
* @param Result|ResultStatement $stmt
* @psalm-param array<string, mixed> $hints
*
* @return Generator<int, mixed>
* @return Generator<array-key, mixed>
*
* @final
*/
@@ -194,9 +194,12 @@ abstract class AbstractHydrator
$this->hydrateRowData($row, $result);
$this->cleanupAfterRowIteration();
if (count($result) === 1) {
yield end($result);
if (count($resultSetMapping->indexByMap) === 0) {
yield end($result);
} else {
yield from $result;
}
} else {
yield $result;
}
@@ -79,7 +79,8 @@ class SimpleObjectHydrator extends AbstractHydrator
// We need to find the correct entity class name if we have inheritance in resultset
if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
$discrColumnName = $this->getSQLResultCasing($this->_platform, $this->class->discriminatorColumn['name']);
$discrColumn = $this->class->getDiscriminatorColumn();
$discrColumnName = $this->getSQLResultCasing($this->_platform, $discrColumn['name']);
// Find mapped discriminator column from the result set.
$metaMappingDiscrColumnName = array_search($discrColumnName, $this->resultSetMapping()->metaMappings, true);
@@ -184,9 +184,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
$class->setPrimaryTable($parent->table);
}
if ($parent) {
$this->addInheritedIndexes($class, $parent);
}
$this->addInheritedIndexes($class, $parent);
if ($parent->cache) {
$class->cache = $parent->cache;
@@ -276,7 +274,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
} else {
assert($parent instanceof ClassMetadataInfo); // https://github.com/doctrine/orm/issues/8746
if (
(! $class->reflClass || ! $class->reflClass->isAbstract())
! $class->reflClass->isAbstract()
&& ! in_array($class->name, $class->discriminatorMap, true)
) {
throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name, $class->rootEntityName);
+45 -34
View File
@@ -20,6 +20,7 @@ use Doctrine\ORM\Id\AbstractIdGenerator;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\ReflectionService;
use InvalidArgumentException;
use LogicException;
use ReflectionClass;
use ReflectionNamedType;
use ReflectionProperty;
@@ -69,6 +70,26 @@ use const PHP_VERSION_ID;
*
* @template-covariant T of object
* @template-implements ClassMetadata<T>
* @psalm-type FieldMapping = array{
* type: string,
* fieldName: string,
* columnName?: string,
* length?: int,
* id?: bool,
* nullable?: bool,
* columnDefinition?: string,
* precision?: int,
* scale?: int,
* unique?: string,
* inherited?: class-string,
* originalClass?: class-string,
* originalField?: string,
* quoted?: bool,
* requireSQLConversion?: bool,
* declared?: class-string,
* declaredField?: string,
* options?: array<string, mixed>
* }
*/
class ClassMetadataInfo implements ClassMetadata
{
@@ -426,25 +447,7 @@ class ClassMetadataInfo implements ClassMetadata
* Whether a unique constraint should be generated for the column.
*
* @var mixed[]
* @psalm-var array<string, array{
* type: string,
* fieldName: string,
* columnName?: string,
* length?: int,
* id?: bool,
* nullable?: bool,
* columnDefinition?: string,
* precision?: int,
* scale?: int,
* unique?: string,
* inherited?: class-string,
* originalClass?: class-string,
* originalField?: string,
* quoted?: bool,
* requireSQLConversion?: bool,
* declaredField?: string,
* options: array<mixed>
* }>
* @psalm-var array<string, FieldMapping>
*/
public $fieldMappings = [];
@@ -495,7 +498,7 @@ class ClassMetadataInfo implements ClassMetadata
* READ-ONLY: The definition of the discriminator column used in JOINED and SINGLE_TABLE
* inheritance mappings.
*
* @psalm-var array<string, mixed>
* @psalm-var array<string, mixed>|null
*/
public $discriminatorColumn;
@@ -509,7 +512,14 @@ class ClassMetadataInfo implements ClassMetadata
* uniqueConstraints => array
*
* @var mixed[]
* @psalm-var array{name: string, schema: string, indexes: array, uniqueConstraints: array}
* @psalm-var array{
* name: string,
* schema: string,
* indexes: array,
* uniqueConstraints: array,
* options: array<string, mixed>,
* quoted?: bool
* }
*/
public $table;
@@ -665,7 +675,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* The ReflectionClass instance of the mapped class.
*
* @var ReflectionClass
* @var ReflectionClass|null
*/
public $reflClass;
@@ -1276,18 +1286,7 @@ class ClassMetadataInfo implements ClassMetadata
* @param string $fieldName The field name.
*
* @return mixed[] The field mapping.
* @psalm-return array{
* type: string,
* fieldName: string,
* columnName?: string,
* inherited?: class-string,
* nullable?: bool,
* originalClass?: class-string,
* originalField?: string,
* scale?: int,
* precision?: int,
* length?: int
* }
* @psalm-return FieldMapping
*
* @throws MappingException
*/
@@ -3090,6 +3089,18 @@ class ClassMetadataInfo implements ClassMetadata
}
}
/**
* @return array<string, mixed>
*/
final public function getDiscriminatorColumn(): array
{
if ($this->discriminatorColumn === null) {
throw new LogicException('The discriminator column was not set.');
}
return $this->discriminatorColumn;
}
/**
* Sets the discriminator values used by this class.
* Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
+5 -5
View File
@@ -15,26 +15,26 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
#[Attribute(Attribute::TARGET_PROPERTY)]
final class Column implements Annotation
{
/** @var string */
/** @var string|null */
public $name;
/** @var mixed */
public $type;
/** @var int */
/** @var int|null */
public $length;
/**
* The precision for a decimal (exact numeric) column (Applies only for decimal column).
*
* @var int
* @var int|null
*/
public $precision = 0;
/**
* The scale for a decimal (exact numeric) column (Applies only for decimal column).
*
* @var int
* @var int|null
*/
public $scale = 0;
@@ -47,7 +47,7 @@ final class Column implements Annotation
/** @var array<string,mixed> */
public $options = [];
/** @var string */
/** @var string|null */
public $columnDefinition;
/**
@@ -249,7 +249,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$field = $this->quoteStrategy->getColumnName($name, $targetClass, $this->platform);
$whereClauses[] = sprintf('te.%s %s ?', $field, $operator);
$params[] = $value;
$paramTypes[] = PersisterHelper::getTypeOfColumn($field, $targetClass, $this->em);
$paramTypes[] = PersisterHelper::getTypeOfField($name, $targetClass, $this->em)[0];
}
$tableName = $this->quoteStrategy->getTableName($targetClass, $this->platform);
@@ -24,7 +24,7 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister
$data = parent::prepareInsertData($entity);
// Populate the discriminator column
$discColumn = $this->class->discriminatorColumn;
$discColumn = $this->class->getDiscriminatorColumn();
$this->columnTypes[$discColumn['name']] = $discColumn['type'];
$data[$this->getDiscriminatorColumnTableName()][$discColumn['name']] = $this->class->discriminatorValue;
@@ -13,7 +13,6 @@ use Doctrine\ORM\Utility\PersisterHelper;
use function array_combine;
use function implode;
use function is_array;
/**
* The joined subclass persister maps a single entity instance to several tables in the
@@ -412,14 +411,15 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
}
$columnList = [];
$discrColumn = $this->class->discriminatorColumn['name'];
$discrColumnType = $this->class->discriminatorColumn['type'];
$discrColumn = $this->class->getDiscriminatorColumn();
$discrColumnName = $discrColumn['name'];
$discrColumnType = $discrColumn['type'];
$baseTableAlias = $this->getSQLTableAlias($this->class->name);
$resultColumnName = $this->getSQLResultCasing($this->platform, $discrColumn);
$resultColumnName = $this->getSQLResultCasing($this->platform, $discrColumnName);
$this->currentPersisterContext->rsm->addEntityResult($this->class->name, 'r');
$this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
$this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumn, false, $discrColumnType);
$this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumnName, false, $discrColumnType);
// Add regular columns
foreach ($this->class->fieldMappings as $fieldName => $mapping) {
@@ -457,7 +457,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
? $baseTableAlias
: $this->getSQLTableAlias($this->class->rootEntityName);
$columnList[] = $tableAlias . '.' . $discrColumn;
$columnList[] = $tableAlias . '.' . $discrColumnName;
// sub tables
foreach ($this->class->subClasses as $subClassName) {
@@ -540,7 +540,7 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
// Add discriminator column if it is the topmost class.
if ($this->class->name === $this->class->rootEntityName) {
$columns[] = $this->class->discriminatorColumn['name'];
$columns[] = $this->class->getDiscriminatorColumn()['name'];
}
return $columns;
@@ -44,16 +44,17 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
$rootClass = $this->em->getClassMetadata($this->class->rootEntityName);
$tableAlias = $this->getSQLTableAlias($rootClass->name);
// Append discriminator column
$discrColumn = $this->class->discriminatorColumn['name'];
$discrColumnType = $this->class->discriminatorColumn['type'];
// Append discriminator column
$discrColumn = $this->class->getDiscriminatorColumn();
$discrColumnName = $discrColumn['name'];
$discrColumnType = $discrColumn['type'];
$columnList[] = $tableAlias . '.' . $discrColumn;
$columnList[] = $tableAlias . '.' . $discrColumnName;
$resultColumnName = $this->getSQLResultCasing($this->platform, $discrColumn);
$resultColumnName = $this->getSQLResultCasing($this->platform, $discrColumnName);
$this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
$this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumn, false, $discrColumnType);
$this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumnName, false, $discrColumnType);
// Append subclass columns
foreach ($this->class->subClasses as $subClassName) {
@@ -100,7 +101,7 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
$columns = parent::getInsertColumnList();
// Add discriminator column to the INSERT SQL
$columns[] = $this->class->discriminatorColumn['name'];
$columns[] = $this->class->getDiscriminatorColumn()['name'];
return $columns;
}
@@ -158,11 +159,12 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
$values[] = $this->conn->quote($discrValues[$subclassName]);
}
$discColumnName = $this->class->getDiscriminatorColumn()['name'];
$values = implode(', ', $values);
$discColumn = $this->class->discriminatorColumn['name'];
$tableAlias = $this->getSQLTableAlias($this->class->name);
return $tableAlias . '.' . $discColumn . ' IN (' . $values . ')';
return $tableAlias . '.' . $discColumnName . ' IN (' . $values . ')';
}
/**
+8
View File
@@ -649,6 +649,10 @@ final class Query extends AbstractQuery
*/
public function setFirstResult($firstResult): self
{
if ($firstResult !== null) {
$firstResult = (int) $firstResult;
}
$this->firstResult = $firstResult;
$this->_state = self::STATE_DIRTY;
@@ -675,6 +679,10 @@ final class Query extends AbstractQuery
*/
public function setMaxResults($maxResults): self
{
if ($maxResults !== null) {
$maxResults = (int) $maxResults;
}
$this->maxResults = $maxResults;
$this->_state = self::STATE_DIRTY;
+1 -1
View File
@@ -214,7 +214,7 @@ class Parser
*/
private $customOutputWalker;
/** @psalm-var list<AST\SelectExpression> */
/** @psalm-var array<string, AST\SelectExpression> */
private $identVariableExpressions = [];
/**
@@ -369,7 +369,7 @@ class ResultSetMappingBuilder extends ResultSetMapping
{
if (isset($entityMapping['discriminatorColumn']) && $entityMapping['discriminatorColumn']) {
$discriminatorColumn = $entityMapping['discriminatorColumn'];
$discriminatorType = $classMetadata->discriminatorColumn['type'];
$discriminatorType = $classMetadata->getDiscriminatorColumn()['type'];
$this->setDiscriminatorColumn($alias, $discriminatorColumn);
$this->addMetaResult($alias, $discriminatorColumn, $discriminatorColumn, false, $discriminatorType);
+3 -3
View File
@@ -465,7 +465,7 @@ class SqlWalker implements TreeWalker
? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.'
: '';
$sqlParts[] = $sqlTableAlias . $class->discriminatorColumn['name'] . ' IN (' . implode(', ', $values) . ')';
$sqlParts[] = $sqlTableAlias . $class->getDiscriminatorColumn()['name'] . ' IN (' . implode(', ', $values) . ')';
}
$sql = implode(' AND ', $sqlParts);
@@ -739,7 +739,7 @@ class SqlWalker implements TreeWalker
// Add discriminator columns to SQL
$rootClass = $this->em->getClassMetadata($class->rootEntityName);
$tblAlias = $this->getSQLTableAlias($rootClass->getTableName(), $dqlAlias);
$discrColumn = $rootClass->discriminatorColumn;
$discrColumn = $rootClass->getDiscriminatorColumn();
$columnAlias = $this->getSQLColumnAlias($discrColumn['name']);
$sqlSelectExpressions[] = $tblAlias . '.' . $discrColumn['name'] . ' AS ' . $columnAlias;
@@ -2091,7 +2091,7 @@ class SqlWalker implements TreeWalker
$sql .= $this->getSQLTableAlias($discrClass->getTableName(), $dqlAlias) . '.';
}
$sql .= $class->discriminatorColumn['name'] . ($instanceOfExpr->not ? ' NOT IN ' : ' IN ');
$sql .= $class->getDiscriminatorColumn()['name'] . ($instanceOfExpr->not ? ' NOT IN ' : ' IN ');
$sql .= $this->getChildDiscriminatorsFromClassMetadata($discrClass, $instanceOfExpr);
return $sql;
+8
View File
@@ -627,6 +627,10 @@ class QueryBuilder
*/
public function setFirstResult($firstResult)
{
if ($firstResult !== null) {
$firstResult = (int) $firstResult;
}
$this->_firstResult = $firstResult;
return $this;
@@ -652,6 +656,10 @@ class QueryBuilder
*/
public function setMaxResults($maxResults)
{
if ($maxResults !== null) {
$maxResults = (int) $maxResults;
}
$this->_maxResults = $maxResults;
return $this;
@@ -151,7 +151,7 @@ EOT
if (empty($metadata)) {
$ui->success('No Metadata Classes to process.');
return;
return 0;
}
foreach ($metadata as $class) {
+5 -1
View File
@@ -1140,7 +1140,11 @@ public function __construct(<params>)
return '';
}
$discrColumn = $metadata->discriminatorColumn;
$discrColumn = $metadata->discriminatorColumn;
if ($discrColumn === null) {
return '';
}
$columnDefinition = 'name="' . $discrColumn['name']
. '", type="' . $discrColumn['type']
. '", length=' . $discrColumn['length'];
@@ -31,7 +31,7 @@ use const DIRECTORY_SEPARATOR;
*/
class EntityRepositoryGenerator
{
/** @psalm-var class-string */
/** @psalm-var class-string|null */
private $repositoryName;
/** @var string */
+1 -1
View File
@@ -239,7 +239,7 @@ class SchemaValidator
}
}
if (! $class->isInheritanceTypeNone() && ! $class->isRootEntity() && ! $class->isMappedSuperclass && array_search($class->name, $class->discriminatorMap, true) === false) {
if (! $class->isInheritanceTypeNone() && ! $class->isRootEntity() && ! $class->reflClass->isAbstract() && ! $class->isMappedSuperclass && array_search($class->name, $class->discriminatorMap, true) === false) {
$ce[] = "Entity class '" . $class->name . "' is part of inheritance hierarchy, but is " .
"not mapped in the root entity '" . $class->rootEntityName . "' discriminator map. " .
'All subclasses must be listed in the discriminator map.';
+189 -39
View File
@@ -85,11 +85,6 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Cache/Persister/Entity/AbstractEntityPersister.php
-
message: "#^If condition is always true\\.$#"
count: 1
path: lib/Doctrine/ORM/Cache/Persister/Entity/AbstractEntityPersister.php
-
message: "#^Parameter \\#3 \\$entry of method Doctrine\\\\ORM\\\\Cache\\\\EntityHydrator\\:\\:loadCacheEntry\\(\\) expects Doctrine\\\\ORM\\\\Cache\\\\EntityCacheEntry, Doctrine\\\\ORM\\\\Cache\\\\CacheEntry given\\.$#"
count: 1
@@ -105,6 +100,11 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Cache/Persister/Entity/ReadWriteCachedEntityPersister.php
-
message: "#^PHPDoc type Doctrine\\\\Common\\\\Cache\\\\Cache\\|Doctrine\\\\Common\\\\Cache\\\\MultiGetCache of property Doctrine\\\\ORM\\\\Cache\\\\Region\\\\DefaultMultiGetRegion\\:\\:\\$cache is not covariant with PHPDoc type Doctrine\\\\Common\\\\Cache\\\\Cache of overridden property Doctrine\\\\ORM\\\\Cache\\\\Region\\\\DefaultRegion\\:\\:\\$cache\\.$#"
count: 1
path: lib/Doctrine/ORM/Cache/Region/DefaultMultiGetRegion.php
-
message: "#^Method Doctrine\\\\ORM\\\\Cache\\\\Region\\\\DefaultRegion\\:\\:getCache\\(\\) should return Doctrine\\\\Common\\\\Cache\\\\CacheProvider but returns Doctrine\\\\Common\\\\Cache\\\\Cache\\.$#"
count: 1
@@ -185,6 +185,11 @@ parameters:
count: 2
path: lib/Doctrine/ORM/EntityManager.php
-
message: "#^Template type T of method Doctrine\\\\ORM\\\\EntityManagerInterface\\:\\:getClassMetadata\\(\\) is not referenced in a parameter\\.$#"
count: 1
path: lib/Doctrine/ORM/EntityManagerInterface.php
-
message: "#^Method Doctrine\\\\ORM\\\\EntityRepository\\:\\:findOneBy\\(\\) should return T\\|null but returns object\\|null\\.$#"
count: 1
@@ -240,6 +245,16 @@ parameters:
count: 1
path: lib/Doctrine/ORM/LazyCriteriaCollection.php
-
message: "#^Offset 'indexes' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php
-
message: "#^Offset 'uniqueConstraints' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/Builder/ClassMetadataBuilder.php
-
message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\:\\:\\$cache\\.$#"
count: 2
@@ -412,7 +427,7 @@ parameters:
-
message: "#^If condition is always true\\.$#"
count: 2
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
-
@@ -422,7 +437,12 @@ parameters:
-
message: "#^Negated boolean expression is always false\\.$#"
count: 3
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
-
message: "#^Offset 'indexes'\\|'uniqueConstraints' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
-
@@ -530,21 +550,6 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
-
message: "#^Array \\(array\\('name' \\=\\> string, 'schema' \\=\\> string, 'indexes' \\=\\> array, 'uniqueConstraints' \\=\\> array\\)\\) does not accept key 'options'\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
-
message: "#^Array \\(array\\('name' \\=\\> string, 'schema' \\=\\> string, 'indexes' \\=\\> array, 'uniqueConstraints' \\=\\> array\\)\\) does not accept key 'quoted'\\.$#"
count: 2
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
-
message: "#^Array \\(array\\<string, array\\|string\\>\\) does not accept true\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
-
message: "#^Call to an undefined method ReflectionProperty\\:\\:getType\\(\\)\\.$#"
count: 3
@@ -566,13 +571,13 @@ parameters:
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
-
message: "#^Parameter \\#2 \\$type of static method Doctrine\\\\ORM\\\\Mapping\\\\MappingException\\:\\:invalidInheritanceType\\(\\) expects string, int given\\.$#"
message: "#^Offset 'schema' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} on left side of \\?\\? always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
-
message: "#^Result of && is always false\\.$#"
count: 2
message: "#^Parameter \\#2 \\$type of static method Doctrine\\\\ORM\\\\Mapping\\\\MappingException\\:\\:invalidInheritanceType\\(\\) expects string, int given\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
-
@@ -770,6 +775,11 @@ parameters:
count: 2
path: lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php
-
message: "#^PHPDoc type array\\<string, int\\> of property Doctrine\\\\ORM\\\\Mapping\\\\Driver\\\\AttributeDriver\\:\\:\\$entityAnnotationClasses is not covariant with PHPDoc type array\\<class\\-string, bool\\|int\\> of overridden property Doctrine\\\\Persistence\\\\Mapping\\\\Driver\\\\AnnotationDriver\\:\\:\\$entityAnnotationClasses\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php
-
message: "#^Parameter \\#1 \\$metadata of static method Doctrine\\\\ORM\\\\Mapping\\\\Builder\\\\EntityListenerBuilder\\:\\:bindEntityListener\\(\\) expects Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata, Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo&Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\<T of object\\> given\\.$#"
count: 1
@@ -965,6 +975,11 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php
-
message: "#^Offset 'version' on \\*NEVER\\* in isset\\(\\) always exists and is always null\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php
-
message: "#^Parameter \\#1 \\$metadata of static method Doctrine\\\\ORM\\\\Mapping\\\\Builder\\\\EntityListenerBuilder\\:\\:bindEntityListener\\(\\) expects Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata, Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\<T of object\\> given\\.$#"
count: 1
@@ -1120,6 +1135,11 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php
-
message: "#^Offset 'usage' on array\\{usage\\: string, region\\?\\: string\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php
-
message: "#^Parameter \\#1 \\$metadata of static method Doctrine\\\\ORM\\\\Mapping\\\\Builder\\\\EntityListenerBuilder\\:\\:bindEntityListener\\(\\) expects Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata, Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\<T of object\\> given\\.$#"
count: 1
@@ -1385,15 +1405,30 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php
-
message: "#^PHPDoc type array\\<string\\> of property Doctrine\\\\ORM\\\\Query\\\\Expr\\\\Andx\\:\\:\\$allowedClasses is not covariant with PHPDoc type array\\<int, class\\-string\\> of overridden property Doctrine\\\\ORM\\\\Query\\\\Expr\\\\Base\\:\\:\\$allowedClasses\\.$#"
count: 1
path: lib/Doctrine/ORM/Query/Expr/Andx.php
-
message: "#^PHPDoc type array\\<string\\> of property Doctrine\\\\ORM\\\\Query\\\\Expr\\\\Orx\\:\\:\\$allowedClasses is not covariant with PHPDoc type array\\<int, class\\-string\\> of overridden property Doctrine\\\\ORM\\\\Query\\\\Expr\\\\Base\\:\\:\\$allowedClasses\\.$#"
count: 1
path: lib/Doctrine/ORM/Query/Expr/Orx.php
-
message: "#^PHPDoc type array\\<string\\> of property Doctrine\\\\ORM\\\\Query\\\\Expr\\\\Select\\:\\:\\$allowedClasses is not covariant with PHPDoc type array\\<int, class\\-string\\> of overridden property Doctrine\\\\ORM\\\\Query\\\\Expr\\\\Base\\:\\:\\$allowedClasses\\.$#"
count: 1
path: lib/Doctrine/ORM/Query/Expr/Select.php
-
message: "#^Property Doctrine\\\\ORM\\\\Query\\\\FilterCollection\\:\\:\\$em \\(Doctrine\\\\ORM\\\\EntityManager\\) does not accept Doctrine\\\\ORM\\\\EntityManagerInterface\\.$#"
count: 1
path: lib/Doctrine/ORM/Query/FilterCollection.php
-
message: "#^Array \\(array\\<int, Doctrine\\\\ORM\\\\Query\\\\AST\\\\SelectExpression\\>\\) does not accept key non\\-empty\\-string\\.$#"
message: "#^Property Doctrine\\\\ORM\\\\Query\\\\FilterCollection\\:\\:\\$filterHash is never written, only read\\.$#"
count: 1
path: lib/Doctrine/ORM/Query/Parser.php
path: lib/Doctrine/ORM/Query/FilterCollection.php
-
message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#"
@@ -1427,14 +1462,19 @@ parameters:
path: lib/Doctrine/ORM/Query/Parser.php
-
message: "#^Result of && is always false\\.$#"
count: 1
message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 3
path: lib/Doctrine/ORM/Query/Parser.php
-
message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 4
path: lib/Doctrine/ORM/Query/Parser.php
message: "#^Offset 'columns' on array\\{name\\: string, entities\\: array, columns\\: array\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php
-
message: "#^Offset 'entities' on array\\{name\\: string, entities\\: array, columns\\: array\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php
-
message: "#^Parameter \\#2 \\$class of static method Doctrine\\\\ORM\\\\Utility\\\\PersisterHelper\\:\\:getTypeOfColumn\\(\\) expects Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata, Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo given\\.$#"
@@ -1481,6 +1521,16 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Query/SqlWalker.php
-
message: "#^Offset 'resultVariable' on array\\{metadata\\: Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata, parent\\: string, relation\\: array, map\\: mixed, nestingLevel\\: int, token\\: array\\} in isset\\(\\) does not exist\\.$#"
count: 3
path: lib/Doctrine/ORM/Query/SqlWalker.php
-
message: "#^Offset string on array\\<int, array\\{class\\: Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata, dqlAlias\\: string, resultAlias\\: string\\}\\> in isset\\(\\) does not exist\\.$#"
count: 1
path: lib/Doctrine/ORM/Query/SqlWalker.php
-
message: "#^Parameter \\#1 \\$entity of static method Doctrine\\\\ORM\\\\OptimisticLockException\\:\\:lockFailed\\(\\) expects object, class\\-string\\<object\\> given\\.$#"
count: 1
@@ -1987,7 +2037,7 @@ parameters:
path: lib/Doctrine/ORM/QueryBuilder.php
-
message: "#^Parameter \\#2 \\$dqlPart of method Doctrine\\\\ORM\\\\QueryBuilder\\:\\:add\\(\\) expects array\\<'join'\\|int, array\\<int\\|string, object\\>\\|string\\>\\|object\\|string, array\\<string, Doctrine\\\\ORM\\\\Query\\\\Expr\\\\Join\\>&nonEmpty given\\.$#"
message: "#^Parameter \\#2 \\$dqlPart of method Doctrine\\\\ORM\\\\QueryBuilder\\:\\:add\\(\\) expects array\\<'join'\\|int, array\\<int\\|string, object\\>\\|string\\>\\|object\\|string, non\\-empty\\-array\\<string, Doctrine\\\\ORM\\\\Query\\\\Expr\\\\Join\\> given\\.$#"
count: 2
path: lib/Doctrine/ORM/QueryBuilder.php
@@ -2026,11 +2076,6 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php
-
message: "#^Method Doctrine\\\\ORM\\\\Tools\\\\Console\\\\Command\\\\ConvertMappingCommand\\:\\:execute\\(\\) should return int but empty return statement found\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php
-
message: "#^Parameter \\#1 \\$metadata of method Doctrine\\\\ORM\\\\Tools\\\\Export\\\\Driver\\\\AbstractExporter\\:\\:setMetadata\\(\\) expects array\\<int, Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata\\>, array\\<Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\> given\\.$#"
count: 1
@@ -2067,7 +2112,47 @@ parameters:
path: lib/Doctrine/ORM/Tools/EntityGenerator.php
-
message: "#^Result of && is always false\\.$#"
message: "#^Offset 'allocationSize' on array\\{sequenceName\\: string, allocationSize\\: string, initialValue\\: string, quoted\\?\\: mixed\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/EntityGenerator.php
-
message: "#^Offset 'indexes' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/EntityGenerator.php
-
message: "#^Offset 'initialValue' on array\\{sequenceName\\: string, allocationSize\\: string, initialValue\\: string, quoted\\?\\: mixed\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/EntityGenerator.php
-
message: "#^Offset 'name' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/EntityGenerator.php
-
message: "#^Offset 'options' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/EntityGenerator.php
-
message: "#^Offset 'schema' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/EntityGenerator.php
-
message: "#^Offset 'sequenceName' on array\\{sequenceName\\: string, allocationSize\\: string, initialValue\\: string, quoted\\?\\: mixed\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/EntityGenerator.php
-
message: "#^Offset 'uniqueConstraints' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/EntityGenerator.php
-
message: "#^Property Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo\\<object\\>\\:\\:\\$lifecycleCallbacks \\(array\\<string, array\\<int, string\\>\\>\\) in isset\\(\\) is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/EntityGenerator.php
@@ -2101,6 +2186,36 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/PhpExporter.php
-
message: "#^Offset 'indexes' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php
-
message: "#^Offset 'name' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php
-
message: "#^Offset 'options' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php
-
message: "#^Offset 'schema' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php
-
message: "#^Offset 'uniqueConstraints' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php
-
message: "#^Offset 'version' on array\\{type\\: string, fieldName\\: string, columnName\\?\\: string, length\\?\\: int, id\\?\\: bool, nullable\\?\\: bool, columnDefinition\\?\\: string, precision\\?\\: int, \\.\\.\\.\\} in isset\\(\\) does not exist\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php
-
message: "#^Parameter \\#1 \\$policy of method Doctrine\\\\ORM\\\\Tools\\\\Export\\\\Driver\\\\AbstractExporter\\:\\:_getChangeTrackingPolicyString\\(\\) expects 1\\|2\\|3, int given\\.$#"
count: 1
@@ -2111,6 +2226,11 @@ parameters:
count: 2
path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php
-
message: "#^Property Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo\\<object\\>\\:\\:\\$lifecycleCallbacks \\(array\\<string, array\\<int, string\\>\\>\\) in isset\\(\\) is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php
-
message: "#^Right side of && is always true\\.$#"
count: 2
@@ -2121,6 +2241,16 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php
-
message: "#^Property Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo\\<object\\>\\:\\:\\$lifecycleCallbacks \\(array\\<string, array\\<int, string\\>\\>\\) in isset\\(\\) is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php
-
message: "#^Property Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo\\<object\\>\\:\\:\\$table \\(array\\<string, array\\|bool\\|string\\>\\) on left side of \\?\\? is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php
-
message: "#^Return type \\(void\\) of method Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\CountWalker\\:\\:walkSelectStatement\\(\\) should be compatible with return type \\(string\\) of method Doctrine\\\\ORM\\\\Query\\\\TreeWalker\\:\\:walkSelectStatement\\(\\)$#"
count: 1
@@ -2131,6 +2261,11 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php
-
message: "#^Offset 'parent' on array\\{metadata\\: Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata, parent\\: string, relation\\: array, map\\: mixed, nestingLevel\\: int, token\\: array\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php
-
message: "#^Return type \\(void\\) of method Doctrine\\\\ORM\\\\Tools\\\\Pagination\\\\LimitSubqueryWalker\\:\\:walkSelectStatement\\(\\) should be compatible with return type \\(string\\) of method Doctrine\\\\ORM\\\\Query\\\\TreeWalker\\:\\:walkSelectStatement\\(\\)$#"
count: 1
@@ -2166,6 +2301,21 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Tools/SchemaTool.php
-
message: "#^Offset 'indexes' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/SchemaTool.php
-
message: "#^Offset 'options' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/SchemaTool.php
-
message: "#^Offset 'uniqueConstraints' on array\\{name\\: string, schema\\: string, indexes\\: array, uniqueConstraints\\: array, options\\: array\\<string, mixed\\>, quoted\\?\\: bool\\} in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/SchemaTool.php
-
message: "#^Binary operation \"&\" between string and 3 results in an error\\.$#"
count: 1
+1 -10
View File
@@ -21,7 +21,7 @@ parameters:
message: '/^Call to an undefined method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getSQLResultCasing\(\)\.$/'
path: lib/Doctrine/ORM/Internal/SQLResultCasing.php
-
message: '/^Parameter \$stmt of method .* has invalid typehint type Doctrine\\DBAL\\Driver\\ResultStatement\.$/'
message: '/^Parameter \$stmt of method .* has invalid type Doctrine\\DBAL\\Driver\\ResultStatement\.$/'
path: lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php
-
message: '/^Class Doctrine\\DBAL\\Driver\\ResultStatement not found\.$/'
@@ -30,15 +30,6 @@ parameters:
message: '/^Call to static method ensure\(\) on an unknown class Doctrine\\DBAL\\ForwardCompatibility\\Result\.$/'
path: lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php
# Forward compatibility for DBAL 3.2
- '/^Call to an undefined method Doctrine\\DBAL\\Cache\\QueryCacheProfile::[gs]etResultCache\(\)\.$/'
-
message: '/^Call to an undefined static method Doctrine\\DBAL\\Configuration::[gs]etResultCache\(\)\.$/'
path: lib/Doctrine/ORM/Configuration.php
-
message: '/^Parameter #3 \$resultCache of class Doctrine\\DBAL\\Cache\\QueryCacheProfile constructor/'
path: lib/Doctrine/ORM/AbstractQuery.php
# False positive
-
message: '/^Variable \$offset in isset\(\) always exists and is not nullable\.$/'
+119 -129
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="4.10.0@916b098b008f6de4543892b1e0651c1c3b92cbfa">
<files psalm-version="4.13.1@5cf660f63b548ccd4a56f62d916ee4d6028e01a3">
<file src="lib/Doctrine/ORM/AbstractQuery.php">
<DeprecatedClass occurrences="1">
<code>IterableResult</code>
@@ -7,9 +7,6 @@
<DeprecatedMethod occurrences="1">
<code>iterate</code>
</DeprecatedMethod>
<DocblockTypeContradiction occurrences="1">
<code>$resultCacheDriver !== null &amp;&amp; ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)</code>
</DocblockTypeContradiction>
<FalsableReturnStatement occurrences="1">
<code>! $filteredParameters-&gt;isEmpty() ? $filteredParameters-&gt;first() : null</code>
</FalsableReturnStatement>
@@ -273,8 +270,7 @@
<code>getCacheFactory</code>
<code>getTimestampRegion</code>
</PossiblyNullReference>
<RedundantConditionGivenDocblockType occurrences="2">
<code>$result</code>
<RedundantConditionGivenDocblockType occurrences="1">
<code>assert($metadata instanceof ClassMetadata)</code>
</RedundantConditionGivenDocblockType>
<UndefinedInterfaceMethod occurrences="9">
@@ -503,10 +499,9 @@
<code>$entityName</code>
<code>$entityName</code>
</ParamNameMismatch>
<PossiblyNullArgument occurrences="3">
<PossiblyNullArgument occurrences="2">
<code>$config-&gt;getProxyDir()</code>
<code>$config-&gt;getProxyNamespace()</code>
<code>$entity</code>
</PossiblyNullArgument>
<PossiblyNullReference occurrences="2">
<code>createCache</code>
@@ -520,15 +515,16 @@
<PropertyTypeCoercion occurrences="1">
<code>new $metadataFactoryClassName()</code>
</PropertyTypeCoercion>
<RedundantCondition occurrences="1">
<RedundantCondition occurrences="2">
<code>is_object($connection)</code>
<code>is_object($connection)</code>
</RedundantCondition>
<RedundantConditionGivenDocblockType occurrences="1">
<code>$this-&gt;filterCollection !== null</code>
</RedundantConditionGivenDocblockType>
<TypeDoesNotContainType occurrences="2">
<code>$connection instanceof Connection</code>
<code>': "' . $connection . '"'</code>
<code>gettype($connection)</code>
</TypeDoesNotContainType>
</file>
<file src="lib/Doctrine/ORM/EntityManagerInterface.php">
@@ -606,9 +602,6 @@
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>$sequenceName</code>
</PossiblyNullPropertyAssignmentValue>
<RedundantCastGivenDocblockType occurrences="1">
<code>(string) $em-&gt;getConnection()-&gt;lastInsertId($this-&gt;sequenceName)</code>
</RedundantCastGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Id/TableGenerator.php">
<PossiblyFalseOperand occurrences="3">
@@ -779,9 +772,7 @@
</RedundantCastGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Mapping/ClassMetadata.php">
<PropertyNotSetInConstructor occurrences="8">
<code>ClassMetadata</code>
<code>ClassMetadata</code>
<PropertyNotSetInConstructor occurrences="6">
<code>ClassMetadata</code>
<code>ClassMetadata</code>
<code>ClassMetadata</code>
@@ -823,13 +814,13 @@
<DeprecatedConstant occurrences="1">
<code>ClassMetadata::GENERATOR_TYPE_UUID</code>
</DeprecatedConstant>
<DeprecatedMethod occurrences="2">
<DeprecatedMethod occurrences="3">
<code>addNamedNativeQuery</code>
<code>addNamedQuery</code>
<code>getName</code>
</DeprecatedMethod>
<DocblockTypeContradiction occurrences="3">
<code>! $class-&gt;reflClass</code>
<code>$class-&gt;reflClass</code>
<DocblockTypeContradiction occurrences="2">
<code>! $definition</code>
<code>$definition</code>
</DocblockTypeContradiction>
<InvalidArrayOffset occurrences="1">
@@ -872,6 +863,9 @@
<code>$parent-&gt;table</code>
<code>$parent-&gt;versionField</code>
</NoInterfaceProperties>
<PossiblyInvalidArrayAssignment occurrences="1">
<code>$subClass-&gt;table[$indexType][$indexName]</code>
</PossiblyInvalidArrayAssignment>
<PossiblyInvalidIterator occurrences="1">
<code>$parentClass-&gt;table[$indexType]</code>
</PossiblyInvalidIterator>
@@ -894,7 +888,7 @@
<code>$subClass-&gt;table</code>
</PropertyTypeCoercion>
<RedundantConditionGivenDocblockType occurrences="2">
<code>$parent</code>
<code>$parent-&gt;idGenerator</code>
<code>$parent-&gt;idGenerator</code>
</RedundantConditionGivenDocblockType>
<UndefinedInterfaceMethod occurrences="17">
@@ -925,13 +919,17 @@
<DeprecatedConstant occurrences="1">
<code>self::GENERATOR_TYPE_UUID</code>
</DeprecatedConstant>
<DeprecatedMethod occurrences="1">
<code>canEmulateSchemas</code>
</DeprecatedMethod>
<DeprecatedProperty occurrences="4">
<code>$this-&gt;columnNames</code>
<code>$this-&gt;columnNames</code>
<code>$this-&gt;columnNames</code>
<code>$this-&gt;columnNames</code>
</DeprecatedProperty>
<DocblockTypeContradiction occurrences="1">
<DocblockTypeContradiction occurrences="2">
<code>! $this-&gt;table</code>
<code>$this-&gt;table</code>
</DocblockTypeContradiction>
<InvalidDocblock occurrences="4">
@@ -940,9 +938,10 @@
<code>protected function _validateAndCompleteOneToOneMapping(array $mapping)</code>
<code>public $inheritanceType = self::INHERITANCE_TYPE_NONE;</code>
</InvalidDocblock>
<InvalidNullableReturnType occurrences="2">
<InvalidNullableReturnType occurrences="3">
<code>ReflectionProperty</code>
<code>ReflectionProperty</code>
<code>getReflectionClass</code>
</InvalidNullableReturnType>
<InvalidPropertyAssignmentValue occurrences="1">
<code>$definition</code>
@@ -971,7 +970,8 @@
<MoreSpecificReturnType occurrences="1">
<code>array{usage: int, region: string|null}</code>
</MoreSpecificReturnType>
<NullableReturnStatement occurrences="2">
<NullableReturnStatement occurrences="3">
<code>$this-&gt;reflClass</code>
<code>$this-&gt;reflFields[$name]</code>
<code>$this-&gt;reflFields[$this-&gt;identifier[0]]</code>
</NullableReturnStatement>
@@ -991,12 +991,17 @@
<code>$queryMapping['resultClass']</code>
<code>$reflService-&gt;getAccessibleProperty($mapping['originalClass'], $mapping['originalField'])</code>
</PossiblyNullArgument>
<PossiblyNullPropertyAssignmentValue occurrences="3">
<code>$reflService-&gt;getClass($this-&gt;name)</code>
<code>$reflService-&gt;getClass($this-&gt;name)</code>
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>null</code>
</PossiblyNullPropertyAssignmentValue>
<PossiblyNullReference occurrences="6">
<PossiblyNullPropertyFetch occurrences="2">
<code>$embeddable-&gt;reflClass-&gt;name</code>
<code>$this-&gt;reflClass-&gt;name</code>
</PossiblyNullPropertyFetch>
<PossiblyNullReference occurrences="9">
<code>getProperty</code>
<code>getProperty</code>
<code>getProperty</code>
<code>getValue</code>
<code>getValue</code>
<code>getValue</code>
@@ -1017,12 +1022,10 @@
<code>$this-&gt;fieldMappings[$idProperty]['columnName']</code>
<code>$this-&gt;fieldMappings[$idProperty]['columnName']</code>
</PossiblyUndefinedArrayOffset>
<PropertyNotSetInConstructor occurrences="8">
<code>$discriminatorColumn</code>
<PropertyNotSetInConstructor occurrences="6">
<code>$idGenerator</code>
<code>$isVersioned</code>
<code>$namespace</code>
<code>$reflClass</code>
<code>$sequenceGeneratorDefinition</code>
<code>$table</code>
<code>$tableGeneratorDefinition</code>
@@ -1045,21 +1048,11 @@
<code>$mapping !== false</code>
<code>$mapping !== false</code>
</RedundantConditionGivenDocblockType>
<RedundantPropertyInitializationCheck occurrences="1"/>
<TooManyArguments occurrences="2">
<code>joinColumnName</code>
<code>joinColumnName</code>
</TooManyArguments>
</file>
<file src="lib/Doctrine/ORM/Mapping/Column.php">
<PossiblyNullPropertyAssignmentValue occurrences="5">
<code>$columnDefinition</code>
<code>$length</code>
<code>$name</code>
<code>$precision</code>
<code>$scale</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/ColumnResult.php">
<MissingConstructor occurrences="1">
<code>$name</code>
@@ -1088,6 +1081,10 @@
</PossiblyFalseOperand>
</file>
<file src="lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php">
<DeprecatedMethod occurrences="2">
<code>canEmulateSchemas</code>
<code>canEmulateSchemas</code>
</DeprecatedMethod>
<MissingClosureParamType occurrences="1">
<code>$joinColumn</code>
</MissingClosureParamType>
@@ -1108,9 +1105,14 @@
<ArgumentTypeCoercion occurrences="1">
<code>$metadata</code>
</ArgumentTypeCoercion>
<DocblockTypeContradiction occurrences="1">
<DocblockTypeContradiction occurrences="2">
<code>! $class</code>
<code>$class</code>
</DocblockTypeContradiction>
<LessSpecificReturnStatement occurrences="1">
<code>$mapping</code>
</LessSpecificReturnStatement>
<MoreSpecificReturnType occurrences="1"/>
<NoInterfaceProperties occurrences="5">
<code>$metadata-&gt;inheritanceType</code>
<code>$metadata-&gt;isEmbeddedClass</code>
@@ -1125,10 +1127,6 @@
<code>$primaryTable['indexes']</code>
<code>$primaryTable['uniqueConstraints']</code>
</PossiblyUndefinedArrayOffset>
<RedundantConditionGivenDocblockType occurrences="2">
<code>isset($column-&gt;columnDefinition)</code>
<code>isset($column-&gt;name)</code>
</RedundantConditionGivenDocblockType>
<UndefinedInterfaceMethod occurrences="32">
<code>addEntityListener</code>
<code>addLifecycleCallback</code>
@@ -1177,6 +1175,10 @@
<code>$value[1]</code>
<code>$value[1]</code>
</InvalidArrayAccess>
<LessSpecificReturnStatement occurrences="1">
<code>$mapping</code>
</LessSpecificReturnStatement>
<MoreSpecificReturnType occurrences="1"/>
<NonInvariantDocblockPropertyType occurrences="1">
<code>$entityAnnotationClasses</code>
</NonInvariantDocblockPropertyType>
@@ -1193,10 +1195,8 @@
<code>assert($method instanceof ReflectionMethod)</code>
<code>assert($property instanceof ReflectionProperty)</code>
</RedundantCondition>
<RedundantConditionGivenDocblockType occurrences="3">
<RedundantConditionGivenDocblockType occurrences="1">
<code>assert($cacheAttribute instanceof Mapping\Cache)</code>
<code>isset($column-&gt;columnDefinition)</code>
<code>isset($column-&gt;name)</code>
</RedundantConditionGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php">
@@ -1291,11 +1291,7 @@
<code>$indexXml-&gt;options</code>
<code>$uniqueXml-&gt;options</code>
</PossiblyInvalidPropertyFetch>
<RedundantCast occurrences="1">
<code>(string) $attributes-&gt;name</code>
</RedundantCast>
<RedundantCondition occurrences="20">
<code>isset($attributes-&gt;name)</code>
<RedundantCondition occurrences="19">
<code>isset($xmlRoot-&gt;cache)</code>
<code>isset($xmlRoot-&gt;embedded)</code>
<code>isset($xmlRoot-&gt;field)</code>
@@ -1587,16 +1583,7 @@
<InvalidDocblock occurrences="1">
<code>final class PersistentCollection extends AbstractLazyCollection implements Selectable</code>
</InvalidDocblock>
<InvalidReturnStatement occurrences="5">
<code>$persister-&gt;slice($this, $offset, $length)</code>
<code>$this-&gt;collection</code>
<code>new ArrayCollection($persister-&gt;loadCriteria($this, $criteria))</code>
<code>parent::slice($offset, $length)</code>
</InvalidReturnStatement>
<InvalidReturnType occurrences="2">
<code>Collection&lt;TKey, T&gt;</code>
<code>array&lt;TKey,T&gt;</code>
</InvalidReturnType>
<InvalidReturnStatement occurrences="1"/>
<MissingParamType occurrences="2">
<code>$key</code>
<code>$offset</code>
@@ -1631,7 +1618,9 @@
<PropertyNotSetInConstructor occurrences="1">
<code>$backRefFieldName</code>
</PropertyNotSetInConstructor>
<RedundantConditionGivenDocblockType occurrences="3">
<RedundantConditionGivenDocblockType occurrences="5">
<code>$this-&gt;em</code>
<code>$this-&gt;em</code>
<code>is_object($this-&gt;collection)</code>
<code>is_object($value) &amp;&amp; $this-&gt;em</code>
<code>is_object($value) &amp;&amp; $this-&gt;em</code>
@@ -1857,9 +1846,6 @@
<PropertyTypeCoercion occurrences="1">
<code>$this-&gt;currentPersisterContext-&gt;sqlTableAliases</code>
</PropertyTypeCoercion>
<RedundantCondition occurrences="1">
<code>($comparison === Comparison::EQ || $comparison === Comparison::IS) &amp;&amp; $value === null</code>
</RedundantCondition>
<RedundantConditionGivenDocblockType occurrences="1">
<code>$this-&gt;insertSql !== null</code>
</RedundantConditionGivenDocblockType>
@@ -1900,11 +1886,6 @@
<code>$columnList</code>
</PossiblyUndefinedVariable>
</file>
<file src="lib/Doctrine/ORM/Persisters/SqlValueVisitor.php">
<RedundantCondition occurrences="1">
<code>($operator === Comparison::EQ || $operator === Comparison::IS) &amp;&amp; $value === null</code>
</RedundantCondition>
</file>
<file src="lib/Doctrine/ORM/Proxy/ProxyFactory.php">
<ArgumentTypeCoercion occurrences="2">
<code>$classMetadata</code>
@@ -1973,9 +1954,6 @@
<code>$queryCacheTTL</code>
<code>Query</code>
</PropertyNotSetInConstructor>
<RedundantCastGivenDocblockType occurrences="1">
<code>(int) $timeToLive</code>
</RedundantCastGivenDocblockType>
<RedundantConditionGivenDocblockType occurrences="4">
<code>$dqlQuery !== null</code>
<code>$rsm !== null</code>
@@ -2203,6 +2181,9 @@
<ArgumentTypeCoercion occurrences="1">
<code>$this-&gt;stringPrimary</code>
</ArgumentTypeCoercion>
<DeprecatedMethod occurrences="1">
<code>getLowerExpression</code>
</DeprecatedMethod>
<PropertyNotSetInConstructor occurrences="1">
<code>$stringPrimary</code>
</PropertyNotSetInConstructor>
@@ -2232,6 +2213,9 @@
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/Functions/SqrtFunction.php">
<DeprecatedMethod occurrences="1">
<code>getSqrtExpression</code>
</DeprecatedMethod>
<PropertyNotSetInConstructor occurrences="1">
<code>$simpleArithmeticExpression</code>
</PropertyNotSetInConstructor>
@@ -2270,6 +2254,9 @@
<ArgumentTypeCoercion occurrences="1">
<code>$this-&gt;stringPrimary</code>
</ArgumentTypeCoercion>
<DeprecatedMethod occurrences="1">
<code>getUpperExpression</code>
</DeprecatedMethod>
<PropertyNotSetInConstructor occurrences="1">
<code>$stringPrimary</code>
</PropertyNotSetInConstructor>
@@ -2636,16 +2623,9 @@
<code>call_user_func($functionClass, $functionName)</code>
<code>call_user_func($functionClass, $functionName)</code>
</DocblockTypeContradiction>
<InvalidArrayOffset occurrences="2">
<code>$this-&gt;identVariableExpressions[$dqlAlias]</code>
<code>$this-&gt;queryComponents[$dqlAlias]</code>
</InvalidArrayOffset>
<InvalidNullableReturnType occurrences="1">
<code>SelectStatement|UpdateStatement|DeleteStatement</code>
</InvalidNullableReturnType>
<InvalidPropertyAssignmentValue occurrences="1">
<code>$this-&gt;identVariableExpressions</code>
</InvalidPropertyAssignmentValue>
<InvalidReturnStatement occurrences="9">
<code>$primary</code>
<code>$this-&gt;CollectionMemberExpression()</code>
@@ -2850,27 +2830,36 @@
<code>$renameMode</code>
<code>$renameMode</code>
</ArgumentTypeCoercion>
<PossiblyNullPropertyFetch occurrences="1">
<code>$classMetadata-&gt;reflClass-&gt;name</code>
</PossiblyNullPropertyFetch>
<PossiblyNullReference occurrences="3">
<code>getShortName</code>
<code>getShortName</code>
<code>getShortName</code>
</PossiblyNullReference>
<PossiblyUndefinedArrayOffset occurrences="1">
<code>$class-&gt;fieldMappings[$this-&gt;fieldMappings[$columnName]]['columnName']</code>
</PossiblyUndefinedArrayOffset>
</file>
<file src="lib/Doctrine/ORM/Query/SqlWalker.php">
<DocblockTypeContradiction occurrences="10">
<code>! ($factor instanceof AST\ConditionalFactor)</code>
<code>$condExpr instanceof AST\ConditionalExpression</code>
<code>$condTerm instanceof AST\ConditionalTerm</code>
<code>$simpleArithmeticExpr instanceof AST\SimpleArithmeticExpression</code>
<DocblockTypeContradiction occurrences="8">
<code>$likeExpr-&gt;stringPattern instanceof AST\Functions\FunctionNode</code>
<code>$likeExpr-&gt;stringPattern instanceof AST\PathExpression</code>
<code>$this-&gt;queryComponents[$dqlAlias]['relation'] === null</code>
<code>''</code>
<code>is_numeric($leftExpr) ? $leftExpr : $this-&gt;conn-&gt;quote($leftExpr)</code>
<code>is_numeric($rightExpr) ? $rightExpr : $this-&gt;conn-&gt;quote($rightExpr)</code>
<code>is_numeric($leftExpr)</code>
<code>is_numeric($rightExpr)</code>
<code>is_string($expression)</code>
<code>is_string($stringExpr)</code>
</DocblockTypeContradiction>
<ImplicitToStringCast occurrences="1">
<code>$expr</code>
</ImplicitToStringCast>
<InvalidArgument occurrences="1">
<InvalidArgument occurrences="4">
<code>$condExpr</code>
<code>$condTerm</code>
<code>$factor</code>
<code>$selectedClass['class']-&gt;name</code>
</InvalidArgument>
<InvalidArrayOffset occurrences="1">
@@ -2941,10 +2930,12 @@
<code>$this-&gt;queryComponents</code>
<code>$this-&gt;selectedClasses</code>
</PropertyTypeCoercion>
<RedundantConditionGivenDocblockType occurrences="5">
<RedundantConditionGivenDocblockType occurrences="7">
<code>$leftExpr instanceof AST\Node</code>
<code>$likeExpr-&gt;stringPattern instanceof AST\InputParameter</code>
<code>$rightExpr instanceof AST\Node</code>
<code>$this-&gt;conn-&gt;quote($leftExpr)</code>
<code>$this-&gt;conn-&gt;quote($rightExpr)</code>
<code>$whereClause !== null</code>
<code>($factor-&gt;not ? 'NOT ' : '') . $this-&gt;walkConditionalPrimary($factor-&gt;conditionalPrimary)</code>
</RedundantConditionGivenDocblockType>
@@ -3239,10 +3230,9 @@
<NullableReturnStatement occurrences="1">
<code>$this-&gt;cacheMode</code>
</NullableReturnStatement>
<PossiblyFalseArgument occurrences="3">
<PossiblyFalseArgument occurrences="2">
<code>$spacePos</code>
<code>$spacePos</code>
<code>strpos($join, '.')</code>
</PossiblyFalseArgument>
<PossiblyFalseOperand occurrences="2">
<code>$spacePos</code>
@@ -3258,13 +3248,6 @@
<PropertyNotSetInConstructor occurrences="1">
<code>$_dql</code>
</PropertyNotSetInConstructor>
<RedundantCastGivenDocblockType occurrences="5">
<code>(bool) $cacheable</code>
<code>(bool) $flag</code>
<code>(int) $cacheMode</code>
<code>(int) $lifetime</code>
<code>(string) $cacheRegion</code>
</RedundantCastGivenDocblockType>
<RedundantConditionGivenDocblockType occurrences="1">
<code>$this-&gt;_dql !== null</code>
</RedundantConditionGivenDocblockType>
@@ -3315,13 +3298,9 @@
<MissingReturnType occurrences="1">
<code>configure</code>
</MissingReturnType>
<PossiblyNullArgument occurrences="2">
<code>$cacheDriver</code>
<PossiblyNullArgument occurrences="1">
<code>$cacheDriver</code>
</PossiblyNullArgument>
<PossiblyNullReference occurrences="1">
<code>deleteAll</code>
</PossiblyNullReference>
</file>
<file src="lib/Doctrine/ORM/Tools/Console/Command/ConvertDoctrine1SchemaCommand.php">
<ArgumentTypeCoercion occurrences="1">
@@ -3352,9 +3331,6 @@
<code>new ClassMetadataExporter()</code>
<code>new EntityGenerator()</code>
</DeprecatedClass>
<InvalidNullableReturnType occurrences="1">
<code>int</code>
</InvalidNullableReturnType>
<MissingReturnType occurrences="1">
<code>configure</code>
</MissingReturnType>
@@ -3494,10 +3470,8 @@
<DeprecatedConstant occurrences="1">
<code>ClassMetadataInfo::GENERATOR_TYPE_UUID</code>
</DeprecatedConstant>
<DocblockTypeContradiction occurrences="3">
<code>$metadata-&gt;reflClass !== null</code>
<DocblockTypeContradiction occurrences="1">
<code>class_exists($metadata-&gt;name)</code>
<code>new ReflectionClass($metadata-&gt;name)</code>
</DocblockTypeContradiction>
<InvalidDocblock occurrences="1">
<code>public function setFieldVisibility($visibility)</code>
@@ -3523,12 +3497,13 @@
<PropertyNotSetInConstructor occurrences="1">
<code>$classToExtend</code>
</PropertyNotSetInConstructor>
<RedundantCastGivenDocblockType occurrences="1">
<RedundantCastGivenDocblockType occurrences="2">
<code>(array) $metadata-&gt;table['options']</code>
<code>(bool) $embeddablesImmutable</code>
</RedundantCastGivenDocblockType>
<RedundantConditionGivenDocblockType occurrences="3">
<code>$metadata-&gt;reflClass</code>
<code>$metadata-&gt;reflClass !== null</code>
<code>$metadata-&gt;sequenceGeneratorDefinition</code>
<code>$metadata-&gt;sequenceGeneratorDefinition</code>
<code>isset($metadata-&gt;lifecycleCallbacks)</code>
</RedundantConditionGivenDocblockType>
</file>
@@ -3538,15 +3513,9 @@
<code>$fullClassName</code>
<code>$fullClassName</code>
</ArgumentTypeCoercion>
<DocblockTypeContradiction occurrences="1">
<code>EntityRepository::class</code>
</DocblockTypeContradiction>
<PossiblyFalseOperand occurrences="1">
<code>strrpos($fullClassName, '\\')</code>
</PossiblyFalseOperand>
<PropertyNotSetInConstructor occurrences="1">
<code>$repositoryName</code>
</PropertyNotSetInConstructor>
<PropertyTypeCoercion occurrences="1">
<code>$repositoryName</code>
</PropertyTypeCoercion>
@@ -3609,6 +3578,10 @@
<NonInvariantDocblockPropertyType occurrences="1">
<code>$_extension</code>
</NonInvariantDocblockPropertyType>
<RedundantConditionGivenDocblockType occurrences="2">
<code>$metadata-&gt;table</code>
<code>$metadata-&gt;table</code>
</RedundantConditionGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php">
<ArgumentTypeCoercion occurrences="3">
@@ -3635,10 +3608,12 @@
<PossiblyNullReference occurrences="1">
<code>addAttribute</code>
</PossiblyNullReference>
<RedundantCondition occurrences="1">
<RedundantCondition occurrences="2">
<code>$field['associationKey']</code>
<code>isset($field['associationKey']) &amp;&amp; $field['associationKey']</code>
</RedundantCondition>
<RedundantConditionGivenDocblockType occurrences="1">
<RedundantConditionGivenDocblockType occurrences="2">
<code>$sequenceDefinition</code>
<code>isset($metadata-&gt;lifecycleCallbacks)</code>
</RedundantConditionGivenDocblockType>
</file>
@@ -3675,6 +3650,10 @@
</RedundantConditionGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Tools/Pagination/CountOutputWalker.php">
<DeprecatedMethod occurrences="2">
<code>getCountExpression</code>
<code>getCountExpression</code>
</DeprecatedMethod>
<MoreSpecificImplementedParamType occurrences="1">
<code>$query</code>
</MoreSpecificImplementedParamType>
@@ -3728,7 +3707,8 @@
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php">
<DocblockTypeContradiction occurrences="2">
<DocblockTypeContradiction occurrences="3">
<code>$AST-&gt;whereClause-&gt;conditionalExpression instanceof ConditionalFactor</code>
<code>$AST-&gt;whereClause-&gt;conditionalExpression instanceof ConditionalPrimary</code>
</DocblockTypeContradiction>
<ImplementedReturnTypeMismatch occurrences="1">
@@ -3740,12 +3720,16 @@
<PossiblyInvalidPropertyAssignmentValue occurrences="1">
<code>$AST-&gt;whereClause-&gt;conditionalExpression</code>
</PossiblyInvalidPropertyAssignmentValue>
<RedundantConditionGivenDocblockType occurrences="1">
<code>$AST-&gt;whereClause-&gt;conditionalExpression instanceof ConditionalExpression</code>
</RedundantConditionGivenDocblockType>
<RedundantConditionGivenDocblockType occurrences="1"/>
</file>
<file src="lib/Doctrine/ORM/Tools/SchemaTool.php">
<DocblockTypeContradiction occurrences="1">
<DeprecatedMethod occurrences="3">
<code>canEmulateSchemas</code>
<code>compare</code>
<code>setExplicitForeignKeyIndexes</code>
</DeprecatedMethod>
<DocblockTypeContradiction occurrences="2">
<code>! $definingClass</code>
<code>$definingClass</code>
</DocblockTypeContradiction>
<MissingClosureParamType occurrences="1">
@@ -3773,6 +3757,11 @@
<code>$indexName</code>
</TypeDoesNotContainType>
</file>
<file src="lib/Doctrine/ORM/Tools/SchemaValidator.php">
<PossiblyNullReference occurrences="1">
<code>isAbstract</code>
</PossiblyNullReference>
</file>
<file src="lib/Doctrine/ORM/Tools/Setup.php">
<DeprecatedClass occurrences="3">
<code>new ClassLoader('Doctrine', $directory)</code>
@@ -3877,7 +3866,8 @@
<code>setValue</code>
<code>setValue</code>
</PossiblyNullReference>
<PossiblyUndefinedMethod occurrences="3">
<PossiblyUndefinedMethod occurrences="4">
<code>addPropertyChangedListener</code>
<code>unwrap</code>
<code>unwrap</code>
<code>unwrap</code>
+18
View File
@@ -30,6 +30,10 @@
<!-- We're calling the deprecated method for BC here. -->
<file name="lib/Doctrine/ORM/Internal/SQLResultCasing.php"/>
<!-- We need to keep the calls for DBAL 2.13 compatibility. -->
<referencedMethod name="Doctrine\DBAL\Cache\QueryCacheProfile::getResultCacheDriver"/>
<referencedMethod name="Doctrine\DBAL\Cache\QueryCacheProfile::setResultCacheDriver"/>
<referencedMethod name="Doctrine\DBAL\Configuration::getResultCacheImpl"/>
<referencedMethod name="Doctrine\DBAL\Configuration::setResultCacheImpl"/>
<referencedMethod name="Doctrine\DBAL\Connection::getSchemaManager"/>
<referencedMethod name="Doctrine\DBAL\Platforms\AbstractPlatform::getGuidExpression"/>
</errorLevel>
@@ -76,6 +80,20 @@
<file name="lib/Doctrine/ORM/Mapping/Driver/AttributeReader.php"/>
</errorLevel>
</NullArgument>
<RedundantCastGivenDocblockType>
<errorLevel type="suppress">
<!-- Can be removed once the "getMaxResults" methods of those classes have native parameter types -->
<file name="lib/Doctrine/ORM/Query.php"/>
<file name="lib/Doctrine/ORM/QueryBuilder.php"/>
</errorLevel>
</RedundantCastGivenDocblockType>
<!-- Workaround for https://github.com/vimeo/psalm/issues/7026 -->
<ReservedWord>
<errorLevel type="suppress">
<directory name="lib"/>
<directory name="tests"/>
</errorLevel>
</ReservedWord>
<TypeDoesNotContainType>
<errorLevel type="suppress">
<file name="lib/Doctrine/ORM/Internal/SQLResultCasing.php"/>
@@ -17,16 +17,14 @@ abstract class GetMetadata
{
/**
* @param string|object $class
* @phpstan-param class-string|object $class
* @psalm-param class-string|object $class
*/
abstract public function getEntityManager($class): EntityManagerInterface;
/**
* @psalm-param class-string<TObject> $class
* @phpstan-param class-string $class
*
* @psalm-return ClassMetadata<TObject>
* @phpstan-return ClassMetadata<object>
*
* @psalm-template TObject of object
*/
@@ -6,6 +6,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\IterableTester;
use Doctrine\Tests\Models\CMS\CmsAddress;
use Doctrine\Tests\Models\CMS\CmsArticle;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\OrmFunctionalTestCase;
@@ -68,4 +69,48 @@ final class QueryIterableTest extends OrmFunctionalTestCase
IterableTester::assertResultsAreTheSame($query);
}
public function testIndexByQueryWithOneResult(): void
{
$user = new CmsUser();
$user->name = 'Antonio J.';
$user->username = 'ajgarlag';
$user->status = 'developer';
$this->_em->persist($user);
$this->_em->flush();
$query = $this->_em->createQuery('SELECT u FROM ' . CmsUser::class . ' u INDEX BY u.username');
IterableTester::assertResultsAreTheSame($query);
}
public function testIndexByQueryWithMultipleResults(): void
{
$article1 = new CmsArticle();
$article1->topic = 'Doctrine 2';
$article1->text = 'This is an introduction to Doctrine 2.';
$article2 = new CmsArticle();
$article2->topic = 'Symfony 2';
$article2->text = 'This is an introduction to Symfony 2.';
$article3 = new CmsArticle();
$article3->topic = 'Laminas';
$article3->text = 'This is an introduction to Laminas.';
$article4 = new CmsArticle();
$article4->topic = 'CodeIgniter';
$article4->text = 'This is an introduction to CodeIgniter.';
$this->_em->persist($article1);
$this->_em->persist($article2);
$this->_em->persist($article3);
$this->_em->persist($article4);
$this->_em->flush();
$this->_em->clear();
$query = $this->_em->createQuery('select a from ' . CmsArticle::class . ' a INDEX BY a.topic');
IterableTester::assertResultsAreTheSame($query);
}
}
@@ -0,0 +1,217 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\ManyToMany;
use Doctrine\Tests\OrmFunctionalTestCase;
/**
* @group GH-9109
*/
class GH9109Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->_schemaTool->createSchema(
[
$this->_em->getClassMetadata(GH9109User::class),
$this->_em->getClassMetadata(GH9109Product::class),
]
);
}
protected function tearDown(): void
{
$this->_schemaTool->dropSchema(
[
$this->_em->getClassMetadata(GH9109User::class),
$this->_em->getClassMetadata(GH9109Product::class),
]
);
parent::tearDown();
}
public function testIssue(): void
{
$userFirstName = 'GH9109Test';
$userLastName = 'UserGH9109';
$productTitle = 'Test product';
$userRepository = $this->_em->getRepository(GH9109User::class);
$user = new GH9109User();
$user->setFirstName($userFirstName);
$user->setLastName($userLastName);
$product = new GH9109Product();
$product->setTitle($productTitle);
$this->_em->persist($user);
$this->_em->persist($product);
$this->_em->flush();
$product->addBuyer($user);
$this->_em->persist($product);
$this->_em->flush();
$this->_em->clear();
$persistedProduct = $this->_em->find(GH9109Product::class, $product->getId());
// assert Product was persisted
self::assertInstanceOf(GH9109Product::class, $persistedProduct);
self::assertEquals($productTitle, $persistedProduct->getTitle());
// assert Product has a Buyer
$count = $persistedProduct->getBuyers()->count();
self::assertEquals(1, $count);
// assert NOT QUOTED will WORK with findOneBy
$user = $userRepository->findOneBy(['lastName' => $userLastName]);
self::assertInstanceOf(GH9109User::class, $user);
self::assertEquals($userLastName, $user->getLastName());
// assert NOT QUOTED will WORK with Criteria
$criteria = Criteria::create();
$criteria->where($criteria->expr()->eq('lastName', $userLastName));
$user = $persistedProduct->getBuyers()->matching($criteria)->first();
self::assertInstanceOf(GH9109User::class, $user);
self::assertEquals($userLastName, $user->getLastName());
// assert QUOTED will WORK with findOneBy
$user = $userRepository->findOneBy(['firstName' => $userFirstName]);
self::assertInstanceOf(GH9109User::class, $user);
self::assertEquals($userFirstName, $user->getFirstName());
// assert QUOTED will WORK with Criteria
$criteria = Criteria::create();
$criteria->where($criteria->expr()->eq('firstName', $userFirstName));
$user = $persistedProduct->getBuyers()->matching($criteria)->first();
self::assertInstanceOf(GH9109User::class, $user);
self::assertEquals($userFirstName, $user->getFirstName());
}
}
/**
* @Entity
*/
class GH9109Product
{
/**
* @var int $id
* @Column(name="`id`", type="integer")
* @Id
* @GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string $title
* @Column(name="`title`", type="string", length=255)
*/
private $title;
/**
* @var Collection|GH9109User[]
* @psalm-var Collection<int, GH9109User>
* @ManyToMany(targetEntity="GH9109User")
*/
private $buyers;
public function __construct()
{
$this->buyers = new ArrayCollection();
}
public function getId(): int
{
return $this->id;
}
public function setTitle(string $title): void
{
$this->title = $title;
}
public function getTitle(): string
{
return $this->title;
}
/**
* @psalm-return Collection<int, GH9109User>
*/
public function getBuyers(): Collection
{
return $this->buyers;
}
public function addBuyer(GH9109User $buyer): void
{
$this->buyers[] = $buyer;
}
}
/**
* @Entity
*/
class GH9109User
{
/**
* @var int
* @Column(name="`id`", type="integer")
* @Id
* @GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
* @Column(name="`first_name`", type="string")
*/
private $firstName;
/**
* @var string
* @Column(name="last_name", type="string")
*/
private $lastName;
public function getId(): int
{
return $this->id;
}
public function getFirstName(): string
{
return $this->firstName;
}
public function setFirstName(string $firstName): void
{
$this->firstName = $firstName;
}
public function getLastName(): string
{
return $this->lastName;
}
public function setLastName(string $lastName): void
{
$this->lastName = $lastName;
}
}
@@ -1119,6 +1119,13 @@ abstract class AbstractMappingDriverTest extends OrmTestCase
$class = $this->createClassMetadata(SingleTableEntityIncompleteDiscriminatorColumnMapping::class);
self::assertEquals('dtype', $class->discriminatorColumn['name']);
}
public function testReservedWordInTableColumn(): void
{
$metadata = $this->createClassMetadata(ReservedWordInTableColumn::class);
self::assertSame('count', $metadata->getFieldMapping('count')['columnName']);
}
}
/**
@@ -1774,3 +1781,42 @@ class SingleTableEntityIncompleteDiscriminatorColumnMappingSub1 extends SingleTa
class SingleTableEntityIncompleteDiscriminatorColumnMappingSub2 extends SingleTableEntityIncompleteDiscriminatorColumnMapping
{
}
/** @Entity */
#[ORM\Entity]
class ReservedWordInTableColumn
{
/**
* @var int
* @Id
* @Column(type="integer")
* @GeneratedValue(strategy="NONE")
*/
#[ORM\Id, ORM\Column(type: 'integer'), ORM\GeneratedValue(strategy: 'NONE')]
public $id;
/**
* @var string|null
* @Column(name="`count`", type="integer")
*/
#[ORM\Column(name: '`count`', type: 'integer')]
public $count;
public static function loadMetadata(ClassMetadataInfo $metadata): void
{
$metadata->mapField(
[
'id' => true,
'fieldName' => 'id',
'type' => 'integer',
]
);
$metadata->mapField(
[
'fieldName' => 'count',
'type' => 'integer',
'columnName' => '`count`',
]
);
}
}
@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
$metadata->mapField(
[
'id' => true,
'fieldName' => 'id',
'type' => 'integer',
]
);
$metadata->mapField(
[
'fieldName' => 'count',
'type' => 'integer',
'columnName' => '`count`',
]
);
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Doctrine\Tests\ORM\Mapping\ReservedWordInTableColumn">
<id name="id" type="integer" column="id">
<generator strategy="NONE"/>
</id>
<field name="count" column="`count`" type="integer"/>
</entity>
</doctrine-mapping>
@@ -0,0 +1,10 @@
Doctrine\Tests\ORM\Mapping\ReservedWordInTableColumn:
type: entity
id:
id:
generator:
strategy: NONE
fields:
count:
type: integer
column: '`count`'
@@ -76,7 +76,7 @@ class SelectSqlGenerationTest extends OrmTestCase
parent::assertEquals(
$sqlToBeConfirmed,
$sqlGenerated,
sprintf('"%s" is not equal of "%s"', $sqlGenerated, $sqlToBeConfirmed)
sprintf('"%s" is not equal to "%s"', $sqlGenerated, $sqlToBeConfirmed)
);
$query->free();
@@ -2116,26 +2116,6 @@ class SelectSqlGenerationTest extends OrmTestCase
'SELECT CONCAT(c0_.id, c0_.name, c0_.status) AS sclr_0 FROM cms_users c0_ WHERE c0_.id = ?'
);
$connMock->setDatabasePlatform(new PostgreSQL94Platform());
$this->assertSqlGeneration(
"SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(u.name, u.status, 's') = ?1",
"SELECT c0_.id AS id_0 FROM cms_users c0_ WHERE c0_.name || c0_.status || 's' = ?"
);
$this->assertSqlGeneration(
'SELECT CONCAT(u.id, u.name, u.status) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1',
'SELECT c0_.id || c0_.name || c0_.status AS sclr_0 FROM cms_users c0_ WHERE c0_.id = ?'
);
$connMock->setDatabasePlatform(new SQLServer2012Platform());
$this->assertSqlGeneration(
"SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE CONCAT(u.name, u.status, 's') = ?1",
"SELECT c0_.id AS id_0 FROM cms_users c0_ WHERE (c0_.name + c0_.status + 's') = ?"
);
$this->assertSqlGeneration(
'SELECT CONCAT(u.id, u.name, u.status) FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1',
'SELECT (c0_.id + c0_.name + c0_.status) AS sclr_0 FROM cms_users c0_ WHERE c0_.id = ?'
);
$connMock->setDatabasePlatform($orgPlatform);
}
@@ -225,6 +225,17 @@ class SchemaValidatorTest extends OrmTestCase
$this->assertEquals([], $ce);
}
/**
* @group 9095
*/
public function testAbstractChildClassNotPresentInDiscriminator(): void
{
$class1 = $this->em->getClassMetadata(Issue9095AbstractChild::class);
$ce = $this->validator->validateClass($class1);
$this->assertEquals([], $ce);
}
}
/**
@@ -256,6 +267,35 @@ class ChildEntity extends MappedSuperclassEntity
{
}
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorMap({"child" = Issue9095Child::class})
*/
abstract class Issue9095Parent
{
/**
* @var mixed
* @Id
* @Column
*/
protected $key;
}
/**
* @Entity
*/
abstract class Issue9095AbstractChild extends Issue9095Parent
{
}
/**
* @Entity
*/
class Issue9095Child extends Issue9095AbstractChild
{
}
/**
* @Entity
*/